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

如何通过Dagger实现主Flavor与其他Flavor共用同一ViewModel实例?

问题分析与解决方案

问题根源

ViewModel的实例存储是基于ViewModelStoreOwner + ViewModel的Class类型作为唯一键的。当前:

  • 主Flavor的MyFragment通过viewModels<MyViewModel>获取实例,所以在MyFragment这个ViewModelStoreOwner中,存储键是MyViewModel::class,对应实例是MyFlavoredViewModel(Dagger绑定已替换)。
  • MyFlavoredFragment请求的是MyFlavoredViewModel::class,这是另一个不同的键,即便是同一个ViewModelStoreOwner,Factory也会创建新的实例,导致不共享。

解决方案

不需要修改主Flavor代码,只调整MyFlavoredFragment的ViewModel获取逻辑,让它用和MyFragment相同的键(MyViewModel::class)去获取实例,再强转为MyFlavoredViewModel即可。

调整后的MyFlavoredFragment代码

class FlavoredFragment: Fragment() {
  @Inject lateinit var viewModelFactory: ViewModelFactory
  private val viewModel: MyFlavoredViewModel by lazy {
    val myFragment = requireParentFragment()
      .childFragmentManager
      .findFragmentByTag(MyFragment.TAG)!!
    
    // 用MyViewModel的类型获取,和MyFragment用同一个存储键
    val baseViewModel = ViewModelProvider(myFragment, viewModelFactory)[MyViewModel::class.java]
    
    // 安全校验(Flavor环境下必然是MyFlavoredViewModel)
    check(baseViewModel is MyFlavoredViewModel) { "ViewModel类型不匹配" }
    baseViewModel
  }
}

为什么这样可行?

  1. MyFlavoredModule中已经将MyViewModel::class的绑定替换为MyFlavoredViewModel,所以MyFragment创建的实例本身就是MyFlavoredViewModel。
  2. 用MyViewModel::class作为键获取,就能拿到MyFragment中已经存在的那个实例,避免创建新对象。

额外说明

  • 不需要使用@Repeatable ViewModelKey,因为我们只需要确保MyViewModel::class对应MyFlavoredViewModel的绑定,当前Dagger配置已经满足这一点。
  • 强转操作在Flavor环境下是安全的,因为主Flavor的MyViewModel被Dagger替换为MyFlavoredViewModel实例,不会出现类型转换异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 16:45:33