使用 Dagger 2 将属性注入 ViewModel

phn*_*mnn 3 android dagger-2

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

异常:UninitializedPropertyAccessException:lateinit 属性行程尚未初始化

主要活动视图模型:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

行程模块:

@Module
class TripModule{
    @Provides
    fun provideTrips(): List<Trip> {

        var list = ArrayList<Trip>()
        list.add(Trip(100,10))
        list.add(Trip(200,20))
        return list
    }
}
Run Code Online (Sandbox Code Playgroud)

应用程序组件:

@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)
}
Run Code Online (Sandbox Code Playgroud)

主要活动:

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!! })
    }
}
Run Code Online (Sandbox Code Playgroud)

mly*_*yko 5

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

\n\n\n\n

1) 为视图模型类创建限定符

\n\n
@MustBeDocumented\n@Target(AnnotationTarget.FUNCTION)\n@Retention(AnnotationRetention.RUNTIME)\n@MapKey\nannotation class ViewModelKey(val value: KClass<out ViewModel>)\n
Run Code Online (Sandbox Code Playgroud)\n\n

2)创建视图模型工厂,它从 dagger 的多重绑定中获取值

\n\n
@Singleton\nclass DaggerViewModelFactory @Inject constructor(\n    private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>\n) : ViewModelProvider.Factory {\n\n    @Suppress("UNCHECKED_CAST")\n    override fun <T : ViewModel> create(modelClass: Class<T>): T {\n        var creator: Provider<out ViewModel>? = creators[modelClass]\n        if (creator == null) {\n            for ((key, value) in creators) {\n                if (modelClass.isAssignableFrom(key)) {\n                    creator = value\n                    break\n                }\n            }\n        }\n        if (creator == null) {\n            throw IllegalArgumentException("unknown model class $modelClass")\n        }\n        try {\n            return creator.get() as T\n        } catch (e: Exception) {\n            throw RuntimeException(e)\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

3)有匕首模块,它将提供工厂(从第2点开始),然后是你的视图模型

\n\n
abstract class YourDaggerModuleWhichThenNeedToBePartOfYourGraphAsIncluded {\n\n    @Binds\n    abstract fun bindViewModelFactory(factory: DaggerViewModelFactory): ViewModelProvider.Factory // this needs to be only one for whole app (therefore marked as `@Singleton`)\n\n    @Binds\n    @IntoMap\n    @ViewModelKey(MainActivityViewModel::class)\n    abstract fun bindMainActivityViewModel(vm: MainActivityViewModel): ViewModel // for every viewmodel you have in your app, you need to bind them to dagger\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

4)在您的活动中,当您获取视图模型时,您需要使用 dagger 中的工厂:(更改的地方在// TODO下面的代码中标记为 \xc2\xa0)

\n\n
class MainActivity : AppCompatActivity() {\n\n    @Inject\n    lateinit var tripsAdapter: TripsAdapter\n\n    @Inject\n    lateinit var viewModelFactory: ViewModelProvider.Factory // TODO this was added to the activity\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n\n        // Inject external dependencies\n        AndroidInjection.inject(this)\n\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_main)\n\n        setupRecyclerView();\n        setUpViewModel();\n    }\n\n    private fun setupRecyclerView() {\n        recycler_view.apply {\n            layoutManager = LinearLayoutManager(context)\n            adapter = tripsAdapter\n        }\n    }\n\n    private fun setUpViewModel(){\n        val model = ViewModelProviders.of(this, viewModelFactory)[MainActivityViewModel::class.java] // TODO this was changed\n\n        model.getTrips().observe(this, Observer { tripsAdapter.trips = it!! })\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

我没有提供将模块包含到 dagger 组件的代码,因为我希望这是您已经做过的事情。

\n\n

您可以在这篇中等文章中阅读更多相关信息(我不是该文章的作者):

\n