Dagger2下的ViewModel
Posted 不会写代码的丝丽
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dagger2下的ViewModel相关的知识,希望对你有一定的参考价值。
前言
本文需要一定的储备知识,可参阅博主其他文章:
Dagger2 生成类初探
viewModel源码分析
假设我们想我们的ViewModel
注入一些Dagger2
所提供的依赖怎么办?直接给ViewModel
构造函数注入?
如下代码
//MyViewModel.java
public class MyViewModel extends ViewModel
@Inject
@Named("ActivityStr")
String applicationMsg;
@Inject
public MyViewModel()
//MainActivity.kt
class MainActivity : AppCompatActivity()
@Inject
@Named("ActivityStr")
lateinit var applicationMsg: String
//直接注入
@Inject
lateinit var viewModel: MyViewModel
override 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
@Override
public <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
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass)
//从集合中返回一个
return (T) viewModelsMap.get(modelClass).get();
Map<Class<?>, Provider<ViewModel>> viewModelsMap;
// /**
// * 构造函数要求dagger2传入一个map.
// * key为viewmodel类名
// */
@Inject
public MyViewModelFactory(
@ViewModuleScope
Map<Class<?>, Provider<ViewModel>> viewModelsMap)
this.viewModelsMap = viewModelsMap;
问题又来了dagger
怎么构造Map<Class<? extends ViewModel>, Provider<ViewModel>>
集合对象?
我们只需要使用Dagger2
的多重绑定即可
@Module
public abstract class ViewModules
@Binds
abstract 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()
@Inject
lateinit var factory: ViewModelProvider.Factory
override 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"
以上是关于Dagger2下的ViewModel的主要内容,如果未能解决你的问题,请参考以下文章
Dagger2:如果没有 @Provides-annotated 方法,就无法提供 ViewModel
如何在 ViewModel 中访问 SharedPreferences?
Dagger MVVM - ViewModel注入为null