Skip to content

四大组件 / 生命周期 / Context — 面试题篇

更新: 5/15/2026 字数: 0 字 时长: 0 分钟


Q1: Activity 的生命周期?A 启动 B 时生命周期调用顺序?

考察点:生命周期理解深度

完整回答

正常生命周期:onCreate → onStart → onResume → onPause → onStop → onDestroy。

A 启动 B:A.onPause → B.onCreate → B.onStart → B.onResume → A.onStop

B 返回 A:B.onPause → A.onRestart → A.onStart → A.onResume → B.onStop → B.onDestroy

关键点:A.onPause 先于 B.onCreate 执行,所以 onPause 中不能做耗时操作,否则会延迟 B 的显示。

追问:如果 B 是透明 Activity 或 Dialog 主题?

A 不会调用 onStop(因为 A 仍然部分可见),只调用 onPause。B 关闭后 A 直接调用 onResume。

追问:配置变更(旋转屏幕)时的生命周期?

onPause → onStop → onSaveInstanceState → onDestroy → onCreate(bundle) → onStart → onRestoreInstanceState → onResume

Activity 被销毁重建。可以通过 android:configChanges="orientation|screenSize" 阻止重建,此时只回调 onConfigurationChanged

加分点:提到 ViewModel 通过 onRetainNonConfigurationInstance 在配置变更时保留,不受销毁重建影响。


Q2: Activity 的四种启动模式?

考察点:Task 和启动模式

完整回答

  • standard:默认模式,每次启动创建新实例
  • singleTop:栈顶复用。已在栈顶则调用 onNewIntent,不在栈顶则新建
  • singleTask:栈内复用。在目标 Task 中查找,存在则 clearTop 并调用 onNewIntent
  • singleInstance:独占一个 Task,系统中只有一个实例

使用场景:

  • singleTop:通知点击打开的页面(避免重复创建)、搜索页面
  • singleTask:App 首页(从任何地方回到首页清除中间页面)
  • singleInstance:来电界面、系统级页面

追问:singleTask 一定会在新 Task 中吗?

不一定。singleTask 首先查找 taskAffinity 匹配的 Task,如果已存在则在该 Task 中复用。默认 taskAffinity 是包名,所以默认情况下 singleTask 的 Activity 会在应用的主 Task 中。只有指定了不同的 taskAffinity 才会创建新 Task。

追问:FLAG_ACTIVITY_CLEAR_TOP 和 singleTask 的区别?

CLEAR_TOP 只是清除目标 Activity 上方的 Activity。如果目标是 standard 模式,会先销毁再重建(不调用 onNewIntent)。singleTask 则是复用已有实例(调用 onNewIntent)。CLEAR_TOP + SINGLE_TOP 的组合效果等同于 singleTask。


Q3: Fragment 的生命周期?为什么要用 viewLifecycleOwner?

考察点:Fragment 双生命周期

完整回答

Fragment 生命周期:onAttach → onCreate → onCreateView → onViewCreated → onStart → onResume → onPause → onStop → onDestroyView → onDestroy → onDetach。

Fragment 有两个生命周期:

  1. Fragment 实例生命周期(onCreate → onDestroy)
  2. View 生命周期(onCreateView → onDestroyView)

当 Fragment 加入 back stack 后按返回,View 被销毁(onDestroyView)但 Fragment 实例还在。再次显示时重新走 onCreateView。

如果在 Fragment 中用 this 作为 LifecycleOwner 观察 LiveData,Fragment 返回 back stack 时 Observer 不会被移除(Fragment 没有 destroy)。再次显示时又注册新的 Observer,导致重复观察。

viewLifecycleOwner 则 Observer 跟随 View 生命周期,onDestroyView 时自动移除。

追问:Fragment 之间怎么通信?

推荐方案:

  1. 共享 ViewModel:by activityViewModels() 获取 Activity 级别的 ViewModel
  2. Fragment Result API:setFragmentResult/setFragmentResultListener
  3. Navigation 的 SavedStateHandle

不推荐:直接引用其他 Fragment、接口回调(耦合度高)。


Q4: Service 的两种启动方式?区别是什么?

考察点:Service 生命周期

完整回答

startService

  • 生命周期:onCreate → onStartCommand → 运行 → onDestroy
  • 调用者与 Service 无绑定关系,调用者销毁 Service 继续运行
  • 需要主动调用 stopSelf() 或 stopService() 停止
  • onStartCommand 返回值决定被杀后重启策略

bindService

  • 生命周期:onCreate → onBind → 运行 → onUnbind → onDestroy
  • 返回 IBinder 供客户端通信
  • 所有客户端解绑后自动销毁
  • 适合需要与 Service 交互的场景

可以同时 start + bind,此时需要同时 stop + unbind 才会销毁。

追问:Android 8.0+ 对后台 Service 有什么限制?

应用进入后台后约 1 分钟,系统会停止后台 Service。解决方案:

  1. 前台 Service:startForeground() 显示通知
  2. WorkManager:适合可延迟的后台任务
  3. JobScheduler:系统调度的任务

Android 12+ 前台 Service 需要声明 foregroundServiceType,Android 14+ 必须指定具体类型。


Q5: ContentProvider 的启动时序?为什么很多库用它做初始化?

考察点:ContentProvider 原理

完整回答

启动时序:Application.attachBaseContext → ContentProvider.onCreate → Application.onCreate

ContentProvider 在 Application.onCreate 之前初始化,且系统会自动实例化 Manifest 中声明的所有 ContentProvider。很多库利用这个特性做自动初始化(如 Firebase、LeakCanary、WorkManager),用户不需要手动在 Application 中调用 init 方法。

缺点:每个 ContentProvider 都会拖慢启动速度(约 2-5ms)。如果多个库都用这种方式,累积影响明显。

Jetpack App Startup 库的解决方案:提供一个统一的 ContentProvider(InitializationProvider),所有库的初始化逻辑注册为 Initializer,合并在一个 ContentProvider 中执行,减少开销。

追问:ContentProvider 的跨进程通信原理?

底层通过 Binder。客户端通过 ContentResolver 发起请求,AMS 查找目标 Provider 的 Binder 引用并返回给客户端。后续客户端直接通过 Binder 与 Provider 通信。大数据传输通过 ParcelFileDescriptor 传递文件描述符,绕过 Binder 1MB 大小限制。


Q6: Context 的继承体系?Application Context 和 Activity Context 有什么区别?

考察点:Context 体系

完整回答

继承关系:

Context(抽象类)
├── ContextImpl(真正实现)
└── ContextWrapper(装饰器)
    ├── Application
    ├── Service
    └── ContextThemeWrapper
        └── Activity

区别:

  • Activity Context 包含主题信息(继承 ContextThemeWrapper),可以启动 Activity、弹 Dialog
  • Application/Service Context 没有主题,不能直接启动 Activity(需要 FLAG_ACTIVITY_NEW_TASK),不能弹 Dialog

使用原则:

  • UI 相关(Dialog、Toast、inflate 布局):用 Activity Context
  • 生命周期长的对象(单例、全局缓存):用 Application Context,避免持有 Activity 导致内存泄漏

追问:为什么不能用 Application Context 弹 Dialog?

Dialog 需要依附于一个 Window,而 Window 需要 WindowManager.LayoutParams 中的 token。Activity 有自己的 Window 和 token,Application Context 没有。用 Application Context 弹 Dialog 会抛 BadTokenException。

加分点:提到 getApplicationContext() 返回的是 Application 对象,getBaseContext() 返回的是 ContextImpl。ContextWrapper 的所有方法都委托给 mBase(ContextImpl)。


Q7: onSaveInstanceState 和 ViewModel 的区别?什么时候用哪个?

考察点:状态保存机制

完整回答

维度onSaveInstanceStateViewModel
存储位置Bundle(序列化到磁盘)内存
大小限制~1MB(Bundle 限制)无限制(受堆内存限制)
配置变更✅ 保留✅ 保留
进程被杀✅ 保留❌ 丢失
数据类型可序列化的简单数据任意对象

选择:

  • 轻量关键数据(搜索关键词、列表位置、页码)→ onSaveInstanceState 或 SavedStateHandle
  • 大量数据(列表数据、网络响应)→ ViewModel
  • 需要进程恢复的关键数据 → SavedStateHandle(ViewModel 中使用 Bundle)

追问:onSaveInstanceState 什么时候调用?

Android 9(API 28)之前:在 onStop 之前调用。 Android 9+ 之后:在 onStop 之后调用。 只在系统可能销毁 Activity 时调用(如旋转屏幕、按 Home 键、切换 App),用户主动按返回键不会调用。


Q8: Activity 的 taskAffinity 是什么?怎么影响启动模式?

考察点:Task 管理

完整回答

taskAffinity 是 Activity 的"亲和力"属性,决定 Activity 倾向于属于哪个 Task。默认值是应用包名。

影响:

  1. singleTask:先查找 taskAffinity 匹配的 Task,找到则在该 Task 中复用/创建 Activity。不同 taskAffinity 会创建新 Task。
  2. FLAG_ACTIVITY_NEW_TASK:如果目标 Activity 的 taskAffinity 与当前 Task 不同,会在匹配的 Task 中启动(或创建新 Task)。
  3. allowTaskReparenting:当 Activity 的 taskAffinity 对应的 Task 来到前台时,Activity 会从当前 Task 移到该 Task。
xml
<activity
    android:name=".DetailActivity"
    android:taskAffinity="com.example.detail"
    android:launchMode="singleTask" />

Q9: Android 的权限机制?运行时权限怎么处理?

考察点:权限系统

完整回答

Android 6.0+ 引入运行时权限,危险权限需要在运行时请求:

kotlin
// 推荐:Activity Result API
val launcher = registerForActivityResult(
    ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
    val cameraGranted = permissions[Manifest.permission.CAMERA] ?: false
    val locationGranted = permissions[Manifest.permission.ACCESS_FINE_LOCATION] ?: false
    if (cameraGranted && locationGranted) {
        // 权限已授予
    } else {
        // 处理拒绝
        if (!shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
            // 用户选择了"不再询问",引导去设置页
        }
    }
}

// 请求
launcher.launch(arrayOf(
    Manifest.permission.CAMERA,
    Manifest.permission.ACCESS_FINE_LOCATION
))

权限最佳实践:

  • 最小权限原则:只请求必要的权限
  • 在使用功能时才请求(不要启动时一次性请求所有权限)
  • 被拒绝后解释为什么需要(shouldShowRequestPermissionRationale)
  • 用户选择"不再询问"后引导去设置页

Q10: IntentFilter 的匹配规则?隐式启动 Activity 的过程?

考察点:Intent 解析

完整回答

隐式 Intent 需要同时匹配 action、category 和 data 三个条件:

  1. action:Intent 的 action 必须与 IntentFilter 中的某一个 action 匹配
  2. category:Intent 的所有 category 都必须在 IntentFilter 中存在。系统会自动添加 CATEGORY_DEFAULT,所以 IntentFilter 必须包含它
  3. data:匹配 URI(scheme://host:port/path)和 mimeType
xml
<intent-filter>
    <action android:name="com.example.SHOW" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="https" android:host="example.com" />
</intent-filter>

追问:startActivity 找不到匹配的 Activity 会怎样?

抛 ActivityNotFoundException。安全做法是先用 intent.resolveActivity(packageManager) 检查,或用 try-catch 包裹。

Android 11+ 包可见性限制:需要在 Manifest 中声明 <queries> 才能查询其他应用的 Activity。


实习面试补充:四大组件基础高频题

实习面试更看重组件“会不会用、生命周期会不会踩坑”,不一定要求一开始就讲 AMS 源码。

Q11: Intent 显式启动和隐式启动有什么区别?

考察点:Intent 基础

完整回答

  • 显式 Intent:明确指定目标组件,通常用于应用内部页面跳转。
  • 隐式 Intent:不指定具体组件,而是通过 action、category、data 让系统匹配能处理的组件,常用于打开浏览器、相机、分享等跨应用场景。
kotlin
// 显式启动
startActivity(Intent(this, DetailActivity::class.java))

// 隐式启动
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://www.example.com"))
startActivity(intent)

追问:隐式启动有什么风险?

可能没有应用能处理,导致 ActivityNotFoundException。启动前可以使用 resolveActivity(packageManager) 判断,或用 try-catch 兜底。


Q12: Activity 和 Fragment 分别适合承担什么职责?

考察点:页面组织、职责划分

完整回答

Activity 通常作为页面容器,负责承载 Fragment、处理系统入口、权限、导航和生命周期协调。Fragment 更适合作为可复用的 UI 模块,负责具体页面内容和交互。

常见实践是单 Activity + 多 Fragment,配合 Navigation 管理页面跳转;也可以多 Activity,但不要把所有业务逻辑都堆在 Activity 中。

加分点:Fragment 有 View 生命周期,访问 ViewBinding 时要在 onDestroyView 置空,观察 LiveData/Flow 时优先绑定 viewLifecycleOwner


Q13: Service 是不是运行在子线程?

考察点:Service 基础误区

完整回答

不是。普通 Service 默认运行在主线程,只是没有界面,并不代表自动在后台线程执行。如果在 Service 中做耗时任务,仍然需要自己切到子线程,否则也可能造成 ANR。

如果是需要长期运行且用户可感知的任务,应使用前台服务并展示通知;如果是可延迟的后台任务,可以考虑 WorkManager。

追问:IntentService 现在还推荐吗?

IntentService 已废弃。现在更推荐根据场景使用 WorkManager、协程、线程池或前台服务。