如何用Dagger 2为ViewPager中同Fragment实例注入独立ViewModel
你的问题核心在于Dagger自定义作用域@MainScope和ViewModel的生命周期管理冲突了。
你给ActivityViewModel添加了@MainScope注解,这个作用域绑定在MainActivity的Dagger子组件上——这意味着Dagger会在MainActivity的生命周期内只创建一个ActivityViewModel实例,成为该子组件内的单例。哪怕你在ViewModelProviders.of(this, viewModelFactory).get(key, ActivityViewModel::class.java)里传入了不同的key,Dagger的creator.get()每次都会返回同一个实例,因为它被@MainScope限定成了单例,完全忽略了ViewModelStore的key机制。
这就导致两个Fragment拿到的是同一个ViewModel实例,它们的LiveData观察者自然会同时收到更新。
1. 移除ActivityViewModel上的@MainScope注解
修改你的ActivityViewModelModule:
@Module abstract class ActivityViewModelModule { // 移除@MainScope @Binds @IntoMap @ViewModelKey(ActivityViewModel::class) abstract fun bindActivityViewModel(viewModel: ActivityViewModel): ViewModel }
这样一来,Dagger不再强制ActivityViewModel成为单例,每次调用creator.get()都会生成新的ViewModel实例。配合你传入的不同key,ViewModelStore会为每个Fragment维护独立的ViewModel实例,各自的LiveData更新就只会通知对应的观察者。
2. 确认ViewModel的获取方式
确保你在Fragment里是通过ViewModelProviders.of(this, viewModelFactory)获取ViewModel(而不是传入activity),这样ViewModel的生命周期会绑定到Fragment本身,加上不同的key,就能实现完全独立的实例。
working_fine分支正常? 因为那个分支没有添加@MainScope,Dagger没有对ViewModel做单例限制,ViewModelProviders的key机制就能正常工作——每个不同的key对应不同的ViewModel实例,自然不会出现跨Fragment的LiveData同步更新问题。
如果你需要在Activity和Fragment之间共享ViewModel,正确的做法是用ViewModelProviders.of(activity, viewModelFactory),利用Android架构组件自带的生命周期作用域,而不是依赖Dagger的自定义作用域。这样既符合Jetpack的设计规范,也能避免作用域冲突的问题。
内容的提问来源于stack exchange,提问作者hushed_voice

