Android MVVM Dagger 2-ViewModelFactory注入

时间:2018-10-21 21:06:40

标签: android mvvm kotlin dagger-2

我正在尝试使用Android Kotlin项目中的Dagger 2执行视图模型注入。到目前为止,我的项目看起来像这样。我的AppComponent看起来像这样

    @AppScope
@Component(modules = [
    ViewModelModule::class,
    AndroidSupportInjectionModule::class,


 AppModule::class,
    BuildersModule::class
])
interface AppComponent {
    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application : App) : Builder
        fun build() : AppComponent
    }

   fun inject(app: App)    

}

我的appModule:

@Module class AppModule

我还创建了Builders模块来提供我的视图:

@Module
abstract class BuildersModule {

    @ContributesAndroidInjector
    abstract fun providesMainActivity() : MainActivity

    @ContributesAndroidInjector()
    abstract fun providesModeMenuActivity(): ModeMenuActivity

}

我的视图模型收藏夹取自github project上的示例

@AppScope
class ViewModelFactory
@Inject constructor(
    private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {

    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        val creator = creators[modelClass] ?:
        creators.asIterable().firstOrNull { modelClass.isAssignableFrom(it.key) }?.value
        ?: throw IllegalArgumentException("unknown model class " + modelClass)

        return try {
            creator.get() as T
        } catch (e: Exception) {
            throw RuntimeException(e)
        }

    }
}

我在ViewModelModule中绑定工厂是这样的:

@Module
abstract class ViewModelModule {

    @Binds
    @IntoMap
    @ViewModelKey(ModeMenuViewModel::class)
    abstract fun bindModeMenuViewModel(modeMenuViewModel: ModeMenuViewModel): ModeMenuViewModel

    @Binds
    abstract fun bindsViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory

}

现在一切都会构建,直到我在以下活动之一中添加ViewModelFacotory注入:

class ModeMenuActivity: AppCompatActivity() {

    @Inject
    lateinit var vmFactory: ViewModelProvider.Factory

 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        AndroidInjection.inject(this)

       val binding: ActivityModeMenuBinding = DataBindingUtil.setContentView(this, R.layout.activity_mode_menu)
        val viewModel = ViewModelProviders.of(this, vmFactory).get(ModeMenuViewModel::class.java)
       binding.ViewModel = viewModel

    }


}

在构建添加@Inject的代码时,出现以下错误:

C:\Users\Maciej\AndroidStudioProjects\AndroidMVVM\app\build\tmp\kapt3\stubs\debug\com\example\maciej\androidmvvm\di\AppComponent.java:8: error: [Dagger/MissingBinding] [dagger.android.AndroidInjector.inject(T)] java.util.Map<java.lang.Class<? extends android.arch.lifecycle.ViewModel>,javax.inject.Provider<android.arch.lifecycle.ViewModel>> cannot be provided without an @Provides-annotated method.
public abstract interface AppComponent {
                ^
      java.util.Map<java.lang.Class<? extends android.arch.lifecycle.ViewModel>,javax.inject.Provider<android.arch.lifecycle.ViewModel>> is injected at
          com.example.maciej.androidmvvm.ViewModelModule.ViewModelFactory.<init>(creators)
      com.example.maciej.androidmvvm.ViewModelModule.ViewModelFactory is injected at
          com.example.maciej.androidmvvm.ViewModelModule.ViewModelModule.bindsViewModelFactory(factory)
      android.arch.lifecycle.ViewModelProvider.Factory is injected at
          com.example.maciej.androidmvvm.ui.common.ModeMenu.ModeMenuActivity.vmFactory
      com.example.maciej.androidmvvm.ui.common.ModeMenu.ModeMenuActivity is injected at
          dagger.android.AndroidInjector.inject(T)
  component path: com.example.maciej.androidmvvm.di.AppComponent ? com.example.maciej.androidmvvm.di.BuildersModule_ProvidesModeMenuActivity.

到目前为止,我在论坛上什么都找不到,所以如果您能告诉我我在做什么错,我将不胜感激。另外我还注意到,当我尝试在“活动”中将视图模型附加到绑定对象时,我会遇到类型不匹配的情况(它显示了不完整的包名称为必需的类型)

2 个答案:

答案 0 :(得分:0)

您的绑定是无操作的,因为您返回的是与参数传递的类型相同的类型,因此请更改返回类型

之前:

travelersMinus(evnet: Event){
        this.changeCount -= 1;
    }

之后:

@Binds
@IntoMap
@ViewModelKey(ModeMenuViewModel::class)
abstract fun bindModeMenuViewModel(modeMenuViewModel: ModeMenuViewModel): ModeMenuViewModel

答案 1 :(得分:0)

最后我找到了解决方案。 Dagger的包裹名称从大写字母开始出现问题。当我将所有包名称都更改为驼峰式时,一切开始起作用。