Android MVVM Dagger 2 - ViewModelFactory Injection - PullRequest
0 голосов
/ 22 октября 2018

Я пытаюсь выполнить инъекцию viewmodel с помощью dagger 2 в проекте Android Kotlin.Пока мой проект выглядит так.У меня 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

@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, я получаю несоответствие типов (оно показывает неполное имя пакета как требуемый тип)

Ответы [ 2 ]

0 голосов
/ 23 октября 2018

Наконец я нашел решение.У Даггера были проблемы с именами моих пакетов, которые начинались с больших букв.Когда я изменил имена всех пакетов на верблюжий чемодан, все начало работать.

0 голосов
/ 22 октября 2018

Ваша привязка не является операцией, поскольку вы возвращаете тот же тип, который вы передаете в качестве аргумента, поэтому измените тип возвращаемого значения следующим образом

До:

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

После:

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