android - 使用 Dagger 2 将属性注入 ViewModel
问题描述
我尝试学习如何使用 Dagger 2。请帮助解决以下异常:
异常:UninitializedPropertyAccessException:lateinit 属性行程尚未初始化
MainActivityViewModel:
class MainActivityViewModel : ViewModel() {
private lateinit var tripsLiveData: MutableLiveData<List<Trip>>
@Inject
lateinit var trips : List<Trip>
fun getTrips() : LiveData<List<Trip>> {
if (!::tripsLiveData.isInitialized){
tripsLiveData = MutableLiveData()
tripsLiveData.value = trips
}
return tripsLiveData
}
}
行程模块:
@Module
class TripModule{
@Provides
fun provideTrips(): List<Trip> {
var list = ArrayList<Trip>()
list.add(Trip(100,10))
list.add(Trip(200,20))
return list
}
}
应用组件:
@Singleton
@Component(modules = [
AndroidSupportInjectionModule::class,
ActivityBuilder::class,
TripModule::class])
interface AppComponent{
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: Application): Builder
fun build(): AppComponent
}
fun inject(app: MyApplication)
}
主要活动:
class MainActivity : AppCompatActivity() {
@Inject
lateinit var tripsAdapter: TripsAdapter
override fun onCreate(savedInstanceState: Bundle?) {
// Inject external dependencies
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupRecyclerView();
setUpViewModel();
}
private fun setupRecyclerView() {
recycler_view.apply {
layoutManager = LinearLayoutManager(context)
adapter = tripsAdapter
}
}
private fun setUpViewModel(){
val model = ViewModelProviders.of(this).get(MainActivityViewModel::class.java)
model.getTrips().observe(this, Observer { tripsAdapter.trips = it!! })
}
}
解决方案
如果您希望您的视图模型成为匕首图的一部分,您需要做几件事 - 使用匕首的多重绑定(只需一次,对于较新的视图模型会更容易)。您将创建新的视图模型工厂,它将负责实例化视图模型。该工厂将成为 dagger 图的一部分,因此将引用通过 dagger 提供的任何内容。然后,您可以通过视图模型的主体@Inject constructor(anyParameterFromDagger: Param)
或内部进行构造函数注入。@Inject lateinit var someParam: Param
1) 为视图模型类创建限定符
@MustBeDocumented
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)
2)创建从匕首的多重绑定中获取值的视图模型工厂
@Singleton
class DaggerViewModelFactory @Inject constructor(
private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
var creator: Provider<out ViewModel>? = creators[modelClass]
if (creator == null) {
for ((key, value) in creators) {
if (modelClass.isAssignableFrom(key)) {
creator = value
break
}
}
}
if (creator == null) {
throw IllegalArgumentException("unknown model class $modelClass")
}
try {
return creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
3)有匕首模块,它将提供工厂(从第2点开始),然后是你的视图模型
abstract class YourDaggerModuleWhichThenNeedToBePartOfYourGraphAsIncluded {
@Binds
abstract fun bindViewModelFactory(factory: DaggerViewModelFactory): ViewModelProvider.Factory // this needs to be only one for whole app (therefore marked as `@Singleton`)
@Binds
@IntoMap
@ViewModelKey(MainActivityViewModel::class)
abstract fun bindMainActivityViewModel(vm: MainActivityViewModel): ViewModel // for every viewmodel you have in your app, you need to bind them to dagger
}
4)在您的活动中,当您获取视图模型时,您需要使用匕首中的工厂:(更改的地方标记为// TODO
下面的代码)
class MainActivity : AppCompatActivity() {
@Inject
lateinit var tripsAdapter: TripsAdapter
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory // TODO this was added to the activity
override fun onCreate(savedInstanceState: Bundle?) {
// Inject external dependencies
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupRecyclerView();
setUpViewModel();
}
private fun setupRecyclerView() {
recycler_view.apply {
layoutManager = LinearLayoutManager(context)
adapter = tripsAdapter
}
}
private fun setUpViewModel(){
val model = ViewModelProviders.of(this, viewModelFactory)[MainActivityViewModel::class.java] // TODO this was changed
model.getTrips().observe(this, Observer { tripsAdapter.trips = it!! })
}
}
我没有提供将模块包含到 dagger 组件的代码,因为我希望这是您已经做过的事情。
您可以在这篇中等文章中阅读更多相关信息(我不是该文章的作者):
推荐阅读
- python - matplotlib.mathtext 函数返回 Unknown symbol: \begin{} 即使 usetex=True 和 \usepackage{amsmath} 正确配置
- python - 在 3.x 程序中有条件地执行部分 python 代码作为 2.x
- angularjs - 为 AngularJS 网站制作全屏加载图像
- linux - 无法安装 vmfs-tools
- java - 等待多个 RxJava observable 完成
- java - 为 Main 方法创建测试方法
- r - 邻接矩阵/社会矩阵的原始数据表
- gf - AppGer.gf 和 AppFre.gf 到 .Pgf 的转换不起作用
- tensorflow - ValueError:无法为张量“ResizeBilinear:0”提供形状(1、26、38、3)的值,其形状为“(1、299、299、3)”
- python - 使用 Python Pandas 连接两个具有范围条件的表