1. Activity生命周期专题:从入门到精通
作为一名有五年Android开发经验的工程师,我面试过上百位候选人,发现Activity生命周期是淘汰率最高的考察点之一。很多开发者虽然能背出生命周期方法的名称,却说不清它们在实际开发中的应用场景和避坑要点。今天我就结合自己踩过的坑和面试官视角,彻底拆解这个看似基础实则暗藏玄机的话题。
2. 生命周期方法全解析
2.1 标准生命周期流程图解
一个典型的Activity会经历以下状态流转:
onCreate() -> onStart() -> onResume() -> [运行状态] -> onPause() -> onStop() -> onDestroy()但实际场景要复杂得多。比如横竖屏切换时会触发:
onPause() -> onStop() -> onSaveInstanceState() -> onDestroy() -> onCreate() -> onStart() -> onRestoreInstanceState() -> onResume()关键经验:onSaveInstanceState()在onStop()前调用,但恢复数据却在onStart()之后,这个时序差异经常导致数据恢复失败。
2.2 各方法使用场景详解
onCreate():
- 必须在此完成视图绑定(setContentView)
- 避免耗时操作(超过5秒会导致ANR)
- 典型应用场景:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 初始化Presenter mPresenter = MainPresenter().apply { attachView(this@MainActivity) } // 恢复保存状态 savedInstanceState?.getString("key")?.let { mData = it } }onResume():
- 最适合注册广播接收器、监听传感器
- 注意与onPause()成对调用:
private lateinit var mSensorManager: SensorManager override fun onResume() { super.onResume() mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL) } override fun onPause() { super.onPause() mSensorManager.unregisterListener(this) }3. 高频面试问题剖析
3.1 横竖屏切换处理方案
面试官常问:"如何避免横竖屏切换时Activity重建?"
方案对比表:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| android:configChanges | 简单直接 | 需手动处理布局 | 简单页面 |
| ViewModel+保存状态 | 符合架构规范 | 代码量稍多 | 复杂页面 |
| 禁止旋转 | 彻底避免问题 | 用户体验差 | 特殊需求 |
推荐实现(ViewModel方案):
class MainViewModel : ViewModel() { val liveData = MutableLiveData<String>() } override fun onCreate(savedInstanceState: Bundle?) { val vm = ViewModelProvider(this).get(MainViewModel::class.java) vm.liveData.observe(this) { data -> textView.text = data } } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putString("tempData", editText.text.toString()) }3.2 后台返回数据丢失问题
当Activity因内存不足被回收后,常见的onActivityResult()数据丢失解决方案:
- 使用ActivityResultContracts(推荐):
// 在onCreate中注册 val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> uri?.let { handleImage(it) } } // 触发选择图片 button.setOnClickListener { getContent.launch("image/*") }- 传统方案注意事项:
override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) // 不要保存Parcelable大对象! outState.putInt("requestCode", mCurrentRequestCode) }4. 高级应用场景
4.1 多窗口模式适配
Android 7.0引入的分屏模式会触发特殊生命周期:
- 进入分屏:
onPause() -> onMultiWindowModeChanged(true)- 调整分屏大小:
onConfigurationChanged()实测发现:在分屏模式下,当另一个窗口获得焦点时,当前Activity只会触发onPause()而不会onStop()
4.2 透明Activity的影响
设置透明主题时:
<style name="TranslucentTheme" parent="Theme.AppCompat"> <item name="android:windowIsTranslucent">true</item> </style>生命周期变化:
- 不会触发onStop()
- 下面的Activity仍保持onPause()状态
- 常见问题:视频播放页面按Home键后仍在播放
5. 性能优化要点
5.1 避免内存泄漏的黄金法则
- 静态变量持有Activity引用:
// 错误示例 companion object { var leakedActivity: Activity? = null } override fun onCreate() { leakedActivity = this }- 未取消的Handler:
private val mHandler = object : Handler(Looper.getMainLooper()) { override fun handleMessage(msg: Message) { // 使用弱引用 activityWeakRef.get()?.let { it.updateUI() } } }5.2 启动速度优化
冷启动时onCreate()耗时分析工具:
adb shell am start -W -n com.example/.MainActivity优化方案:
- 延迟初始化:使用App Startup库
- 布局优化:减少嵌套层级
- 避免在主线程读取SharedPreferences
6. 疑难问题排查指南
6.1 生命周期顺序异常
当出现以下现象时:
- onResume()在onStart()之前调用
- onCreate()被多次调用
可能原因:
- 在子线程操作UI导致异常
- 错误使用了recreate()
- 主题设置不当(如透明主题)
6.2 常见崩溃场景
- 在onSaveInstanceState()之后修改View:
// 错误示例 button.setOnClickListener { startActivity(Intent(this, SecondActivity::class.java)) finish() // 可能导致IllegalStateException }- 异步回调时Activity已销毁:
api.getData { response -> // 必须检查isDestroyed if (!isDestroyed) { updateUI(response) } }7. 最新特性适配
7.1 Android 12折叠屏支持
新增生命周期回调:
override fun onPostResume() { super.onPostResume() windowManager.currentWindowMetrics.let { val foldingFeature = it.bounds // 处理折叠状态变化 } }7.2 多进程Activity注意事项
在AndroidManifest中声明:
<activity android:name=".RemoteActivity" android:process=":remote"/>特殊行为:
- 每个进程有独立生命周期实例
- 不能直接传递Parcelable对象
- 需要改用Messenger通信
8. 架构设计最佳实践
8.1 MVVM模式下的生命周期管理
使用LifecycleObserver的推荐写法:
class MyObserver(private val context: Context) : DefaultLifecycleObserver { override fun onResume(owner: LifecycleOwner) { (context as? MainActivity)?.let { it.bindLocationUpdates() } } } // 在Activity中 lifecycle.addObserver(MyObserver(this))8.2 组合使用Jetpack组件
完整生命周期解决方案:
class MainActivity : AppCompatActivity() { private val viewModel: MainViewModel by viewModels() private val savedStateHandle: SavedStateHandle by lazy { SavedStateHandleController.create( this, viewModelStore, arguments ).handle } override fun onCreate() { super.onCreate() // 自动处理配置变化 viewModel.liveData.observe(this) { data -> // 更新UI } } }9. 面试实战技巧
9.1 高频问题应答策略
当被问到:"为什么onStart()中不适合做耗时操作?"
标准回答结构:
- 原理层面:onStart()仍属于界面准备阶段
- 性能影响:可能导致跳转卡顿
- 替代方案:使用协程+加载状态提示
- 实际案例:在XX项目中因此出现白屏问题
9.2 白板编程常考题目
"实现一个在onPause()时自动保存编辑框内容的基类:"
abstract class StateSaverActivity : AppCompatActivity() { private val editTextMap = mutableMapOf<Int, String>() protected fun registerEditText(editText: EditText) { editTextMap[editText.id] = editText.text.toString() editText.addTextChangedListener(object : TextWatcher { override fun afterTextChanged(s: Editable?) { editTextMap[editText.id] = s.toString() } // 其他回调省略... }) } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putSerializable("editTextStates", HashMap(editTextMap)) } }10. 工具链推荐
10.1 生命周期监控工具
- Android Studio的Lifecycle插件:
// build.gradle debugImplementation 'androidx.lifecycle:lifecycle-process:2.4.0'- 命令行监控:
adb shell dumpsys activity activities | grep Hist10.2 日志优化方案
使用Lifecycle-aware的日志工具:
class LifecycleLogger(private val tag: String) : DefaultLifecycleObserver { override fun onCreate(owner: LifecycleOwner) { Log.d(tag, "onCreate") } // 其他方法省略... } // 使用方式 lifecycle.addObserver(LifecycleLogger("MainActivity"))在项目实践中,我发现很多团队会自定义LifecycleObserver来实现统一的权限申请、埋点上报等横切关注点。比如我们可以在BaseActivity中这样集成:
abstract class BaseActivity : AppCompatActivity() { init { lifecycle.addObserver(object : DefaultLifecycleObserver { override fun onResume(owner: LifecycleOwner) { checkPermissions() } override fun onDestroy(owner: LifecycleOwner) { uploadPageDuration() } }) } }这种模式既避免了在每个Activity中重复编写模板代码,又能确保生命周期处理的统一性。特别是在处理混合开发场景时,比如WebView的内存管理,通过LifecycleObserver可以完美解决Native与H5页面的生命周期同步问题。