You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

当前Android开发中正确获取Application类实例的最优方式?

Android 获取 Application 实例的最优方式

问题场景

1. 错误的实例创建方式

现代Android开发者codelabs中的示例代码如下:

class CustomApplication: Application() {
    lateinit var container: AppContainer
    lateinit var context: Context

    override fun onCreate() {
        super.onCreate()
        container = AppContainer()
        context = applicationContext
    }
}

fun CreationExtras.CustomApplication(): CustomApplication=
    (this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as CustomApplication)

但直接通过CustomApplication().context访问时,context会返回null——因为这种写法是每次调用都新建一个Application实例,而只有系统初始化的Application实例才会触发onCreate生命周期方法,手动创建的实例不会执行该方法。

2. 有风险的单例实现

另一种单例写法虽然能正常获取实例,但IDE会抛出内存泄漏警告:

class CustomApplication: Application() {
    lateinit var container: AppContainer
    lateinit var context: Context

    override fun onCreate() {
        super.onCreate()
        instance = this
        container = AppContainer()
        context = applicationContext
    }

    companion object {
        lateinit var instance: CustomApplication
    }
}

警告内容:

Do not place Android context classes in static fields (static reference to CustomApplication which has field context pointing to Context); this is a memory leak


最优实现方案

1. ViewModel场景:通过Jetpack规范获取(推荐)

上述codelabs中的CreationExtras扩展函数是正确的,但不能手动创建CustomApplication实例,要在ViewModel的初始化流程中使用:

// 方式一:通过AndroidViewModel构造参数传入
class MyViewModel(private val app: CustomApplication) : AndroidViewModel(app) {
    fun doSomething() {
        val container = app.container
        // 直接使用app实例(本身就是Context)
    }
}

// 方式二:在ViewModelFactory中利用CreationExtras获取
class MyViewModelFactory : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
        val app = extras.CustomApplication()
        return MyViewModel(app) as T
    }
}

这种方式直接获取系统初始化好的Application实例,完全符合Android生命周期规范,无内存泄漏风险。

2. 无Context场景:优化后的单例实现

如果需要在工具类等无法直接拿到Context的场景获取实例,可优化单例写法避免警告:

class CustomApplication : Application() {
    lateinit var container: AppContainer

    override fun onCreate() {
        super.onCreate()
        container = AppContainer()
        // 无需单独存储context,Application本身就是Context子类
    }

    companion object {
        @Volatile
        private var instance: CustomApplication? = null

        fun getInstance(): CustomApplication {
            return instance ?: synchronized(this) {
                instance ?: throw IllegalStateException("CustomApplication 尚未初始化")
            }
        }
    }
}

说明:

  • 移除了单独的context字段,直接用getInstance()获取的实例作为Context使用(因为Application继承自Context),消除IDE的内存泄漏警告。
  • 用双重校验锁+@Volatile保证线程安全,避免多线程场景下的初始化问题。

3. 有Context场景:直接通过Context转换

在任何持有Context的地方(比如Activity、Fragment),都可以直接通过applicationContext获取:

fun getCustomApp(context: Context): CustomApplication {
    return context.applicationContext as CustomApplication
}

这种方式灵活且安全,不需要依赖单例,是日常开发中最常用的方式之一。


总结

  • ViewModel场景:优先用AndroidViewModel构造参数或CreationExtras获取,符合Jetpack规范。
  • 无Context场景:使用优化后的双重校验锁单例,避免内存泄漏警告。
  • 有Context场景:直接通过context.applicationContext强转获取,简单高效。

内容的提问来源于stack exchange,提问作者NullPointerException

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 17:52:46