Android - Context详解

75 阅读2分钟

Context 基本概念

Context 是一个抽象类,它代表了应用程序的环境信息。主要用途包括:

  1. 访问应用程序资源
  2. 启动 Activity、Service
  3. 获取系统服务
  4. 获取应用程序目录
  5. 创建 UI 组件

Context 的类型

  1. Application Context

    • 生命周期最长,与应用程序生命周期一致
    • 通过 getApplicationContext() 获取
    • 适用于单例模式
  2. Activity Context

    • 生命周期与 Activity 一致
    • Activity 本身就是 Context
    • 用于 UI 相关操作
  3. Service Context

    • 生命周期与 Service 一致
    • Service 本身也是 Context

使用示例

class ExampleActivity : AppCompatActivity() {
    fun contextExample() {
        // 1. 获取资源
        val drawable = context.getDrawable(R.drawable.icon)
        
        // 2. 启动 Activity
        val intent = Intent(context, SecondActivity::class.java)
        startActivity(intent)
        
        // 3. 获取系统服务
        val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        
        // 4. 获取应用目录
        val filesDir = context.filesDir
    }
}

注意事项

  1. 内存泄漏风险
    • 避免在单例中持有 Activity Context
    • 使用 Application Context 代替 Activity Context(适用场景下)
// 错误示例
class MySingleton private constructor(private val context: Context) {
    companion object {
        @Volatile private var instance: MySingleton? = null
        
        fun getInstance(context: Context): MySingleton {
            return instance ?: synchronized(this) {
                instance ?: MySingleton(context).also { instance = it }
            }
        }
    }
}

// 正确示例
class MySingleton private constructor(private val context: Context) {
    companion object {
        @Volatile private var instance: MySingleton? = null
        
        fun getInstance(context: Context): MySingleton {
            return instance ?: synchronized(this) {
                instance ?: MySingleton(context.applicationContext).also { instance = it }
            }
        }
    }
}
  1. 选择合适的 Context

    • UI 相关操作使用 Activity Context
    • 应用级别操作使用 Application Context
    • 注意生命周期影响
  2. 避免 Context 泄露

    • 在异步操作中使用 WeakReference
    • 及时释放不需要的 Context 引用
class MyAsyncTask(activity: Activity) {
    private val activityReference: WeakReference<Activity> = WeakReference(activity)
    
    fun doInBackground() {
        val activity = activityReference.get() ?: return
        // 使用 activity
    }
}
  1. 不要传递错误的 Context
    • Dialog 要使用 Activity Context,不能使用 Application Context
    • Toast 可以使用 Application Context

最佳实践

  1. 需要在应用程序整个生命周期中使用的场景,使用 Application Context
  2. 涉及到 UI 操作的场景,使用 Activity Context
  3. 在单例模式中,优先使用 Application Context
  4. 注意处理异步操作中的 Context 引用
  5. 根据实际场景选择合适的 Context 类型

记住这些原则可以帮助你避免很多常见的 Context 相关问题,写出更稳定的应用程序。