【问题标题】:Android MVVM Dagger 2 - ViewModelFactory InjectionAndroid MVVM Dagger 2 - ViewModelFactory 注入
【发布时间】:2018-10-21 21:06:39
【问题描述】:

我正在尝试在 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)    

}

我的应用模块:

@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.

到目前为止,我在论坛上找不到任何东西,所以如果你能告诉我我做错了什么,我将不胜感激。我还注意到,当我尝试在 Activity 中将视图模型附加到我的绑定对象时,我得到类型不匹配(它显示不完整的包名称作为所需类型)

【问题讨论】:

  • 我只看了几分钟,但我认为 @ViewModelKey 将您的 ViewModel 映射到 KClass,而不是 Java 类
  • 可以添加ModeMenuViewModel的代码吗?

标签: android mvvm kotlin dagger-2


【解决方案1】:

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

之前:

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

之后:

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

【讨论】:

  • 明确一点,它并不完全是 NOOP,因为它将视图模型绑定到地图中。但是,它没有为 Dagger 提供足够的信息来连接这些点。或者,您可以这样做:``` @Binds abstract fun bindsModeMenuViewModel(modeMenuViewModel: ModeMenuViewModel): ViewModel @Binds @IntoMap @ViewModelKey(ModeMenuViewModel::class) abstract fun bindModeMenuViewModelMap(modeMenuViewModel: ViewModel): ViewModel ```
【解决方案2】:

终于找到了解决办法。 Dagger 对我的包名从大写字母开始有问题。当我将所有包名称更改为驼峰式时,一切都开始工作了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-08
    • 1970-01-01
    • 2022-09-30
    • 1970-01-01
    相关资源
    最近更新 更多