1. Activity生命周期概述
在Android开发中,Activity作为应用的核心组件,其生命周期管理是每个开发者必须掌握的基础知识。Activity生命周期指的是一个Activity从创建到销毁的完整过程,以及在这个过程中可能经历的各种状态变化。
1.1 为什么需要理解生命周期
想象一下你正在使用一个视频播放应用:
- 当接到电话时,视频会自动暂停
- 挂断电话后,视频又能从暂停处继续播放
- 旋转手机时,界面能自动适应新的屏幕方向
- 切换到其他应用再返回时,进度不会丢失
这些流畅的用户体验背后,正是Activity生命周期管理的功劳。如果处理不当,可能会出现:
- 意外崩溃
- 资源浪费(如后台继续播放音频)
- 用户数据丢失
- 电池快速耗尽等问题
1.2 生命周期状态与回调方法
Activity主要有以下几种状态:
- 已创建(Created)
- 已启动(Started)
- 已恢复(Resumed)
- 已暂停(Paused)
- 已停止(Stopped)
- 已销毁(Destroyed)
每个状态转换时,系统都会调用对应的回调方法,开发者可以在这些方法中执行适当的操作。这些回调方法共同构成了Activity的生命周期流程图。
2. 核心生命周期方法详解
2.1 onCreate() - 初始化之地
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 初始化UI组件 val textView = findViewById<TextView>(R.id.text_view) // 恢复保存的状态 savedInstanceState?.let { textView.text = it.getString("text_content") } // 初始化ViewModel viewModel = ViewModelProvider(this).get(MainViewModel::class.java) }关键点:
- 必须调用
super.onCreate() - 通常在这里执行一次性初始化操作
savedInstanceState用于恢复被系统销毁前的状态- 避免在这里执行耗时操作,否则会影响启动速度
常见错误:
- 忘记调用父类方法
- 在setContentView之前访问视图
- 执行网络请求等阻塞UI的操作
2.2 onStart() - 准备亮相
override fun onStart() { super.onStart() // 注册广播接收器 registerReceiver(batteryReceiver, IntentFilter(Intent.ACTION_BATTERY_CHANGED)) // 启动位置更新 locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, MIN_TIME_MS, MIN_DISTANCE_M, locationListener ) }适用场景:
- 注册系统广播
- 启动位置监听
- 初始化需要在界面可见时运行的组件
注意事项:
- 与onCreate不同,onStart可能被多次调用
- 确保与onStop配对使用,避免资源泄漏
2.3 onResume() - 前台焦点
override fun onResume() { super.onResume() // 恢复动画 animationView.resumeAnimation() // 获取相机权限后重新打开相机 if (hasCameraPermission()) { openCamera() } // 更新UI数据 updateUserProfile() }典型用途:
- 恢复暂停的动画
- 重新初始化传感器
- 刷新可能过时的数据
- 获取独占资源(如相机)
重要特性:
- Activity在此状态时位于栈顶并与用户交互
- 可能频繁进出此状态(如来电、权限对话框)
2.4 onPause() - 暂停处理
override fun onPause() { // 暂停正在进行的操作 mediaPlayer.pause() // 释放独占资源 releaseCamera() // 保存临时数据 preferences.edit().putInt("last_position", currentPosition).apply() super.onPause() }最佳实践:
- 必须快速执行(系统会等待方法完成)
- 适合保存简单数据到SharedPreferences
- 不适合执行耗时操作(如数据库写入)
- 注意调用super.onPause()的顺序(通常最后调用)
2.5 onStop() - 后台处理
override fun onStop() { // 取消网络请求 requestJob?.cancel() // 注销广播接收器 unregisterReceiver(batteryReceiver) // 保存数据到数据库 viewModel.saveUserData() super.onStop() }与onPause的区别:
- Activity完全不可见时调用
- 适合执行相对耗时的保存操作
- 在多窗口模式下可能不会调用
2.6 onDestroy() - 最终清理
override fun onDestroy() { // 释放资源 mediaPlayer.release() sensorManager.unregisterListener(this) // 清理Handler防止内存泄漏 handler.removeCallbacksAndMessages(null) super.onDestroy() }调用场景:
- 用户主动退出(按返回键)
- 调用finish()
- 配置变更(如旋转屏幕)
- 系统回收资源
注意:不能依赖此方法保存数据,因为可能不会被调用
3. 状态保存与恢复
3.1 处理配置变更
当屏幕旋转等配置变更发生时,Activity会被销毁并重建。保存状态的两种方式:
- 使用ViewModel:存储界面相关数据
class MainViewModel : ViewModel() { val userInput = MutableLiveData<String>() }- 使用onSaveInstanceState:保存简单数据
override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putString("edit_text", editText.text.toString()) }3.2 恢复UI状态的最佳实践
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 使用保存的状态恢复UI val restoredText = savedInstanceState?.getString("edit_text") ?: "" editText.setText(restoredText) // 结合ViewModel viewModel.userInput.observe(this) { text -> editText.setText(text) } }推荐方案:
- 简单数据:Bundle
- 复杂数据:ViewModel + 持久化存储
- 列表位置:RecyclerView自带恢复机制
4. 多窗口模式下的生命周期
Android 7.0引入的多窗口模式带来了新的生命周期挑战:
4.1 分屏模式下的行为
- 两个Activity都处于"已启动"但只有一个是"已恢复"状态
- 焦点切换时会频繁调用onPause/onResume
4.2 画中画模式(视频应用)
override fun onPictureInPictureModeChanged(isInPiP: Boolean) { if (isInPiP) { // 进入画中画时简化UI controlsView.visibility = View.GONE } else { // 恢复正常模式 controlsView.visibility = View.VISIBLE } }适配建议:
- 在onStop中释放资源要更谨慎
- 使用isChangingConfigurations区分配置变更和正常退出
- 测试各种窗口尺寸下的表现
5. 常见问题与解决方案
5.1 生命周期相关崩溃
问题1:在onDestroy中访问已经为null的View
解决方案:
// 错误方式 override fun onDestroy() { textView.text = "Goodbye" // 可能崩溃 super.onDestroy() } // 正确方式 override fun onDestroy() { if (!isChangingConfigurations) { // 仅在实际退出时执行 saveData() } super.onDestroy() }问题2:异步回调导致的内存泄漏
解决方案:
// 使用lifecycleScope自动取消协程 lifecycleScope.launch { // 网络请求代码 } // 或者手动管理 private val job = Job() override fun onCreate() { viewModel.data.observe(this) { data -> // 更新UI } } override fun onDestroy() { job.cancel() super.onDestroy() }5.2 生命周期感知组件
使用LifecycleObserver简化生命周期管理:
class MyLocationListener(private val lifecycle: Lifecycle) : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_START) fun start() { // 开始监听位置 } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun stop() { // 停止监听位置 } } // 在Activity中使用 val listener = MyLocationListener(lifecycle) lifecycle.addObserver(listener)5.3 测试生命周期
使用AndroidX Test测试生命周期行为:
@RunWith(AndroidJUnit4::class) class MainActivityTest { @Test fun testLifecycle() { val scenario = launchActivity<MainActivity>() // 模拟生命周期变化 scenario.moveToState(Lifecycle.State.CREATED) scenario.moveToState(Lifecycle.State.STARTED) scenario.moveToState(Lifecycle.State.RESUMED) // 验证状态 // ... scenario.close() } }6. 现代Android开发的最佳实践
随着Jetpack组件和Compose的普及,生命周期管理有了新的模式:
6.1 使用ViewModel保存数据
class MainViewModel : ViewModel() { private val _data = MutableLiveData<String>() val data: LiveData<String> = _data fun loadData() { viewModelScope.launch { _data.value = repository.fetchData() } } }6.2 在Compose中处理生命周期
@Composable fun MyScreen(viewModel: MainViewModel) { val data by viewModel.data.observeAsState() // 自动处理生命周期的效果 LaunchedEffect(Unit) { viewModel.loadData() } // UI内容 Text(text = data ?: "Loading...") }6.3 使用Flow替代LiveData
class MainViewModel : ViewModel() { val data: Flow<String> = repository.dataFlow init { viewModelScope.launch { repository.startFetching() } } } // 在Activity中收集 lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.data.collect { data -> updateUI(data) } } }掌握Activity生命周期是Android开发的基础,但随着架构组件的演进,我们有了更多工具来简化生命周期管理。关键在于理解原理,根据应用场景选择合适的方法,并通过充分测试确保各种场景下的稳定表现。