代码之家  ›  专栏  ›  技术社区  ›  Luis Abreu

dagger2和android:加载模块,在地图上注入viewmodel

  •  1
  • Luis Abreu  · 技术社区  · 8 年前

    我已经开始使用匕首2了,所以还有很多东西要学。我想知道是否有人能给我指出正确的方向。

    因此,我创建了一个模块,用于注册活动使用的视图模型。看起来是这样的:

    @Module
    abstract class ViewModelModule {
        @Binds
        internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
    
        @Binds
        @IntoMap
        @ViewModelKey(MainActivityViewModel::class)
        internal abstract fun bindMainActivityViewModel(viewModel: MainActivityViewModel): ViewModel
    
        @Binds
        @IntoMap
        @ViewModelKey(ShowDetailsViewModel::class)
        abstract fun bindShowDetaislViewModel(viewModel: ShowDetailsViewModel): ViewModel
    }
    

    ViewModelKey 是一个简单的助手注释类,如下所示:

    @Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
    @Retention(AnnotationRetention.RUNTIME)
    @MapKey
    annotation class ViewModelKey (val value: KClass<out ViewModel>) {
    }
    

    这个 ViewModelModule

    @Singleton
    @Component(
            modules=[
                AndroidSupportInjectionModule::class,
                AppModule::class,
                DatabaseModule::class,
                NewsServiceModule::class,
                JobBindingModule::class,
                ViewModelModule::class,
                PreferencesModule::class,
                ActivityBindingModule::class
            ]
    )
    interface AppComponent: AndroidInjector<MyApp> {
        @Component.Builder
        abstract class Builder: AndroidInjector.Builder<MyApp>()
    }
    

    这是密码 ActivityBindingModule

    @Module
    abstract class ActivityBindingModule {
        @ActivityScoped
        @ContributesAndroidInjector()
        internal abstract fun mainActivity(): MainActivity
    
        @ActivityScoped
        @ContributesAndroidInjector
        internal abstract fun showDetailsActivity(): ShowDetailsActivity
    }
    

    在内部,每个活动都用如下代码实例化视图模型(在 onCreate

    //view model code
    _viewModel = ViewModelProviders.of(this, viewModelFactory)[ShowDetailsViewModel::class.java]
    

    如你所料, viewModelFactory 作为字段注入:

    @Inject lateinit var viewModelFactory: ViewModelProvider.Factory
    

    为了完整起见,下面是我的视图模型工厂的代码:

    @Singleton
    class ViewModelFactory @Inject constructor(private val viewModels: MutableMap<Class<out ViewModel>, Provider<ViewModel>>) : ViewModelProvider.Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T
            = viewModels[modelClass]?.get() as T
    

    这段代码可以工作,但似乎可以改进。看完文档后,我觉得我可以重构我的 ViewModeModule 这样它就可以简单地实例化我的 ViewModelFactory

    为了测试这个,我从移动 ShowDetailsViewModel 新模块只有一个条目:

    @Module
    internal abstract class DetailsModule {
        @Binds
        @IntoMap
        @ViewModelKey(ShowDetailsViewModel::class)
        abstract fun bindShowDetaislViewModel(viewModel: ShowDetailsViewModel): ViewModel
    
    }
    

    @Module
    abstract class ViewModelModule {
        @Binds
        internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
    
        @Binds
        @IntoMap
        @ViewModelKey(MainActivityViewModel::class)
        internal abstract fun bindMainActivityViewModel(viewModel: MainActivityViewModel): ViewModel
    }
    

    我已经更新了 所以看起来像这样:

    @Module
    abstract class ActivityBindingModule {
        @ActivityScoped
        @ContributesAndroidInjector()
        internal abstract fun mainActivity(): MainActivity
    
        @ActivityScoped
        @ContributesAndroidInjector(modules = [DetailsModule::class])
        internal abstract fun showDetailsActivity(): ShowDetailsActivity
    }
    

    DetailsModule (它实例化 )到 ContributeAndroidInjector 应用于 showDetailsActivity

    现在,我肯定错过了一些东西,因为这样做后,我总是得到以下例外:

    java.lang.IllegalStateException: ViewModelProviders.of(th…ilsViewModel::class.java] must not be null
    

    MainActivityViewModel

    我认为,将每个视图模型和声明移动到子组件使用的每个a模块中,仍然应该允许它注册到由向顶部组件注册的模块注入的映射中。我错了吗?是什么让我错过了这项工作?

    谢谢。

    1 回复  |  直到 8 年前
        1
  •  5
  •   David Medenjak    8 年前

    问题在于 ViewModelFactory 存在 @Singleton 它不会得到任何你在子组件中添加的绑定。把示波器从你的工厂里移走或者把它弄好 @ActivityScoped

    活动( @活动范围 )有权进入工厂( @单子 @单子 )无权从较低的范围使用或创建ViewModel( ). 所以把工厂移到同一个范围( @活动范围 )将授予它创建相关viewmodel的权限。

    推荐文章