Android Dagger Hilt:共享ViewModel是否需添加作用域注解?
嘿,我来帮你理清这个问题!首先得纠正一个关键误解:ViewModel默认不是应用级单例,它的生命周期是绑定到你获取它时指定的ViewModelStoreOwner(比如Activity或Fragment)的。你遇到的Fragment销毁时ViewModel跟着销毁的情况,本质是每个Fragment都创建了自己的ViewModel实例,而不是共享Activity的那一个。
关于Dagger Hilt中ViewModel的作用域
首先明确:ViewModel本身不需要添加Hilt的作用域注解(比如@Singleton、@ActivityScoped这些)。Hilt的@ViewModelInject只是负责帮你注入ViewModel构造函数里的依赖(比如你的Repo、RxSharedPrefsRepo),而ViewModel的实例生命周期是由ViewModelStoreOwner决定的,和Hilt的依赖作用域是两个独立的概念。
如何让Activity和Fragment共享同一个ViewModel
问题的核心不在ViewModel的注入写法,而在获取ViewModel的方式:
- 在你的
MainActivity中,正常获取ViewModel:private val viewModel: MainActivityViewModel by viewModels() - 在两个Fragment中,必须传入Activity作为
ViewModelStoreOwner,而不是用Fragment自身的:
如果你不用KTX扩展,用原始的private val viewModel: MainActivityViewModel by viewModels({ requireActivity() })ViewModelProvider写法也是一样的:val viewModel = ViewModelProvider(requireActivity()).get(MainActivityViewModel::class.java)
这样一来,三个组件(Activity+两个Fragment)就会共享同一个ViewModel实例,只有当Activity销毁时,这个ViewModel才会被清理,Fragment的销毁不会影响它的生命周期。
再说说你的ViewModel代码
你当前的ViewModel写法是完全正确的:
class MainActivityViewModel @ViewModelInject constructor( private val repo: Repo, private val rxSharedPrefsRepo: RxSharedPrefsRepo, private val resourcesRepo: ResourcesRepo, @Assisted private val savedStateHandle: SavedStateHandle ) : ViewModel() { // ...你的业务逻辑 }
@ViewModelInject和@Assisted SavedStateHandle的使用都符合Hilt的规范,不需要修改这部分代码。
额外补充:Hilt作用域注解的用途
如果你的依赖(比如Repo)需要和Activity同生命周期,可以给它加@ActivityScoped注解,但这只是控制依赖本身的实例范围,和ViewModel的生命周期没有直接关联。ViewModel的生命周期始终由绑定的ViewModelStoreOwner决定。
内容的提问来源于stack exchange,提问作者Mackalester

