Dagger2下的ViewModel
前言
本文需要一定的储备知识,可参阅博主其他文章:
Dagger2 生成类初探
viewModel源码分析
假设我们想我们的ViewModel注入一些Dagger2所提供的依赖怎么办?直接给ViewModel构造函数注入?
如下代码
//MyViewModel.java
public class MyViewModel extends ViewModel {@Inject@Named("ActivityStr")String applicationMsg;@Injectpublic MyViewModel() {}}
//MainActivity.kt
class MainActivity : AppCompatActivity() {@Inject@Named("ActivityStr")lateinit var applicationMsg: String//直接注入@Injectlateinit var viewModel: MyViewModeloverride fun onCreate(savedInstanceState: Bundle?) {AndroidInjection.inject(this);super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)}
}
上面的代码没有编译问题,并且viewModel也会被注入ActivityStr字符串,但是viewmodel会丢失状态!!
上面的代码在旋转屏幕时,viewmodel会被重建,因为viewmodel没有放入activity.viewModelStore.
如何将viewmoel放入activity.viewModelStore?仅能通过ViewModelProvider构造的viewmodel才会放入.
- 如下代码:
override fun onCreate(savedInstanceState: Bundle?) {AndroidInjection.inject(this);super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val viewModelProvider =ViewModelProvider(viewModelStore, ViewModelProvider.NewInstanceFactory())//用ViewModelProvider创建的viewmodel会放入viewModelStore.从而保证回收时viewmodel不会重建.val viewmodel = viewModelProvider.get(MyViewModel::class.java)}
所以我们可以通过自定义一个ViewModelProvider.Factory给viewModelProvider,然后通过自定义Factory获取dagger生成的viewmodel返回即可.
//MyViewModelFactory.java
public class MyViewModelFactory implements ViewModelProvider.Factory {@Overridepublic <T extends ViewModel> T create(@NonNull Class<T> modelClass) {return null;}
}
问题又来了MyViewModelFactory又怎么拿到对应的dagger生成viewmodel?
在这种情况下仅能将自己也交付给dagger
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface ViewModuleScope {}@Singleton
public class MyViewModelFactory implements ViewModelProvider.Factory {@NonNull@Overridepublic <T extends ViewModel> T create(@NonNull Class<T> modelClass) {//从集合中返回一个return (T) viewModelsMap.get(modelClass).get();}Map<Class<?>, Provider<ViewModel>> viewModelsMap;// /**
// * 构造函数要求dagger2传入一个map.
// * key为viewmodel类名
// */@Injectpublic MyViewModelFactory(@ViewModuleScopeMap<Class<?>, Provider<ViewModel>> viewModelsMap) {this.viewModelsMap = viewModelsMap;}}
问题又来了dagger怎么构造Map集合对象?
我们只需要使用Dagger2的多重绑定即可
@Module
public abstract class ViewModules {@Bindsabstract ViewModelProvider.Factory bindViewModelFactory(MyViewModelFactory factory);@Binds@IntoMap@ViewModuleScope@ClassKey(MyViewModel.class)abstract ViewModel provideViewModel(MyViewModel myViewModel);@Binds@IntoMap@ViewModuleScope@ClassKey(MyViewModel2.class)abstract ViewModel provideViewModel2(MyViewModel2 myViewModel);}
实际使用
class MainActivity : AppCompatActivity() {@Injectlateinit var factory: ViewModelProvider.Factoryoverride fun onCreate(savedInstanceState: Bundle?) {AndroidInjection.inject(this);super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val viewModelProvider = ViewModelProvider(this, factory)val myViewModel = viewModelProvider[MyViewModel::class.java]Log.e("MainActivity","viewModel ${myViewModel.hashCode()}")}
}
输出:
E/MainActivity: viewModel 197683938
-----------------旋转屏幕----------E/MainActivity: viewModel 197683938
另外关于网上流传的自定义MapKey,和上面原理一样就不在过多说明.不过需要注意添加下面的依赖
compileOnly "com.google.auto.value:auto-value-annotations:1.8.1"kapt "com.google.auto.value:auto-value:1.8.1"
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
