当前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

