gpt4 book ai didi

android - 使用 Dagger 2 将属性注入(inject) ViewModel

转载 作者:行者123 更新时间:2023-11-29 23:20:45 27 4
gpt4 key购买 nike

我尝试学习如何使用 Dagger 2。请帮助解决以下异常:

Exception: UninitializedPropertyAccessException: lateinit property trips has not been initialized

主 Activity View 模型:

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)
}

主要 Activity :

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!! })
}
}

最佳答案

如果您希望您的 View 模型成为 Dagger 图的一部分,您需要做几件事 - 使用 Dagger 的多重绑定(bind)(只需一次,对于较新的 View 模型,它会更容易)。您将创建新的 View 模型工厂,它将负责实例化 View 模型。该工厂将成为 Dagger 图的一部分,因此将引用通过 Dagger 提供的任何内容。然后,您可以通过 @Inject constructor(anyParameterFromDagger: Param)@Inject lateinit var someParam: Param 在 vi​​ewmodel 体内注入(inject)构造函数。

1) 为 View 模型类创建限定符

@MustBeDocumented
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)

2) 创建从 Dagger 的多重绑定(bind)中获取值的 View 模型工厂

@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) 有 dagger 模块,它将提供工厂(从第 2 点开始),然后是你的 View 模型

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) 在您的 Activity 中,当您获得 View 模型时,您需要使用 dagger 中的工厂:(在下面的代码中标记为 //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 组件的代码,因为我希望这是您已经做过的事情。

您可以阅读更多相关信息,例如在这个medium article (我不是文章的作者):

关于android - 使用 Dagger 2 将属性注入(inject) ViewModel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54347924/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com