如何创建带有Context输入参数的ViewModel实例?
解决ViewModel传入Context的正确方式
直接给ViewModel传Context会导致两个问题:一是系统默认的viewModel()方法无法自动注入参数,二是ViewModel生命周期长于UI组件,持有普通Context容易引发内存泄漏。下面是两种正确的实现方案:
方案一:使用AndroidViewModel(推荐)
AndroidViewModel是ViewModel的子类,专门为Android环境设计,它的构造参数是Application(全局Context),不会因为UI组件销毁而泄漏,系统也能自动注入这个参数。
修改ViewModel类:
class MyViewModel(application: Application) : AndroidViewModel(application) { // 获取全局Context,可安全使用 private val appContext = application.applicationContext // 示例:使用Context执行操作 fun doSomething() { Toast.makeText(appContext, "操作执行", Toast.LENGTH_SHORT).show() } }
创建实例的方式和之前一样,无需手动传参:
val myViewModel: MyViewModel = viewModel()
方案二:自定义ViewModelFactory(仅当需要Activity/Fragment Context时使用)
如果必须依赖Activity/Fragment的Context(比如需要主题、资源等),可以通过自定义Factory来传参,但必须用WeakReference包装Context,避免内存泄漏。
步骤1:创建ViewModelFactory类
class MyViewModelFactory(private val context: Context) : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>): T { if (modelClass.isAssignableFrom(MyViewModel::class.java)) { // 用WeakReference包装Context,防止内存泄漏 return MyViewModel(WeakReference(context)) as T } throw IllegalArgumentException("无法创建未知类型的ViewModel") } }
步骤2:修改ViewModel类
class MyViewModel(private val contextRef: WeakReference<Context>) : ViewModel() { // 使用时先获取Context,注意判空 private val context: Context? get() = contextRef.get() fun doSomethingWithActivityContext() { context?.let { // 这里可以使用Activity/Fragment的Context Toast.makeText(it, "使用Activity Context", Toast.LENGTH_SHORT).show() } } }
步骤3:创建ViewModel实例
在Activity或Fragment中:
val myViewModel = ViewModelProvider(this, MyViewModelFactory(requireContext()))[MyViewModel::class.java]
注意事项
- 优先使用方案一,
ApplicationContext是全局唯一的,不会引发内存泄漏,使用成本最低。 - 方案二中必须用
WeakReference,并且每次使用Context前都要判空,避免UI组件销毁后Context为空导致的空指针异常。
内容的提问来源于stack exchange,提问作者GVG
相关产品推荐
相关产品推荐

