分类: Android 基础

  • Android Activity 生命周期完全指南

    为什么需要理解生命周期?

    Android 系统的资源管理机制会导致 Activity 在用户无感知的情况下被销毁和重建。如果不正确处理生命周期,轻则丢失用户数据,重则导致应用崩溃。

    生命周期回调方法

    Activity 类提供了六个核心回调方法:

    • onCreate() — 系统创建 Activity 时调用。必须在此方法中执行初始化逻辑(如 setContentView),且只会调用一次。
    • onStart() — Activity 即将对用户可见时调用。
    • onResume() — Activity 开始与用户交互时调用。此时 Activity 位于栈顶。
    • onPause() — 系统即将启动或恢复另一个 Activity 时调用。应在此释放 CPU 密集型资源。
    • onStop() — Activity 对用户不再可见时调用。
    • onDestroy() — Activity 被销毁前调用。这是最后一个回调。

    常见场景的生命周期流转

    启动 Activity:onCreate → onStart → onResume

    按下 Home 键:onPause → onStop

    从 Home 返回:onRestart → onStart → onResume

    旋转屏幕:onPause → onStop → onDestroy → onCreate → onStart → onResume

    启动另一个 Activity(覆盖但不完全遮挡):onPause(新 Activity 主题为透明或 Dialog)

    onSaveInstanceState 的作用

    当 Activity 可能被系统意外销毁时(如旋转屏幕),系统会调用 onSaveInstanceState() 方法。你应该在此方法中将需要保存的临时数据存入 Bundle,然后在 onCreate() 或 onRestoreInstanceState() 中恢复。

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putInt("scrollPosition", recyclerView.computeVerticalScrollOffset())
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        savedInstanceState?.getInt("scrollPosition")?.let {
            recyclerView.scrollTo(0, it)
        }
    }

    最佳实践

    • onCreate 中只做必要的初始化,耗时操作放到后台线程。
    • onPause 中释放独占资源(如相机、传感器)。
    • onStop 中执行较重的清理工作(如保存数据到数据库)。
    • 始终考虑”Android 可能随时杀死你的进程”这一点来设计应用。
  • 深入理解 Android 的 Context:你用对了吗?

    Context 是什么?

    Context 是 Android 中最核心的抽象之一,它代表了一个应用环境的全局信息。几乎所有 Android 组件都需要 Context——启动 Activity、创建 View、访问资源、打开数据库,都离不开它。

    Context 的类型

    整个应用进程中存在两种 Context:

    • Application Context:与应用生命周期绑定。getApplicationContext() 返回。全局唯一。
    • Activity Context:与 Activity 生命周期绑定。this 或 getContext()(在 Activity 中)。
    // Application Context
    val appCtx = context.applicationContext
    // Activity Context
    val activityCtx = this  // 在 Activity 内部

    什么时候用哪个?

    场景 推荐 Context
    启动 Activity Activity Context(需要任务栈信息)
    显示 Dialog Activity Context
    Layout Inflation Activity Context(会使用正确主题)
    Toast Application Context
    初始化单例 Application Context(避免内存泄漏!)
    启动 Service Activity Context(Android 8.0+ 有限制)
    获取资源(string/color/drawable) 两者均可
    注册 BroadcastReceiver 两者均可,取决于生命周期需求

    常见错误

    1. 单例持有 Activity Context

    // ❌ 危险!Activity 无法被 GC
    object UserManager {
        lateinit var context: Context
    }
    
    // ✅ 正确做法
    object UserManager {
        lateinit var context: Application
        fun init(app: Application) {
            context = app
        }
    }

    2. 使用 Application Context 显示 Dialog

    // ❌ 会崩溃:Unable to add window — token null
    AlertDialog.Builder(applicationContext).show()
    
    // ✅ 使用 Activity Context
    AlertDialog.Builder(this).show()  // this 是 Activity

    3. 静态变量持有 View 引用

    // ❌ View 隐式持有 Activity Context
    companion object {
        var staticView: View? = null
    }

    Context 的继承关系

    Context 是一个抽象类,有两个直接子类:ContextWrapper 和 ContextImpl。Activity、Application、Service 都继承自 ContextWrapper,内部持有一个 ContextImpl 实例作为真正的实现。

    总结

    记住一条黄金法则:如果引用的生命周期比 Activity 长,就用 ApplicationContext,否则用 Activity Context。这样你就能避免大部分 Context 相关的内存泄漏问题。

沪ICP备2026038898号-1