Ошибка Dagger MissingBinding при внедрении ViewModels - PullRequest
0 голосов
/ 21 мая 2019

Я новичок в кинжале и хочу использовать его для введения ViewModels (наряду с другими объектами, такими как репозитории). Когда я пытаюсь скомпилировать приложение, появляется эта ошибка:

e: C:\Project\...\app\build\tmp\kapt3\stubs\debug\com\myapp\di\AppComponent.java:16: error: [Dagger/MissingBinding] java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> cannot be provided without an @Provides-annotated method.

public abstract interface AppComponent {
                ^
      java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at
          com.myapp.di.ViewModelFactory(viewModels)
      com.myapp.di.ViewModelFactory is injected at
          com.myapp.di.ViewModelModule.bindViewModelFactory(factory)
      androidx.lifecycle.ViewModelProvider.Factory is injected at
          com.myapp.ui.activity.MainActivity.viewModelFactory
      com.myapp.ui.activity.MainActivity is injected at
          dagger.android.AndroidInjector.inject(T) [com.myapp.di.AppComponent ? com.myapp.di.ActivityModule_ContributeMainActivity.MainActivitySubcomponent]
  The following other entry points also depend on it:
      dagger.android.AndroidInjector.inject(T) [com.myapp.di.AppComponent ? com.myapp.di.ActivityModule_ContributeItemsFrament.ItemsFragmentSubcomponent]

Возможно, есть одна глупая ошибка, которая мешает компиляции.

Компонент кинжала:

@Singleton
@Component(modules = [AndroidSupportInjectionModule::class, AppModule::class, DatabaseModule::class, ViewModelModule::class, ActivityModule::class])
interface AppComponent {

    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: MyCustomApplication): Builder

        fun build(): AppComponent
    }

    fun inject(app: MyCustomApplication)
}

AppModule:

@Module
class AppModule {

    @Inject
    lateinit var app: Application

    @Provides
    @Singleton
    fun provideAppContext(): Context = app.applicationContext
}

ActivityModule:

@Module
abstract class ActivityModule {

    @ContributesAndroidInjector
    abstract fun bindMainActivity(): MainActivity

    @ContributesAndroidInjector
    abstract fun contributeMainFrament(): MainFragment
}

ViewModelModule:

@Module
abstract class ViewModelModule {

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

    @Binds
    @IntoMap
    @ViewModelKey(MainViewModel::class)
    abstract fun mainViewModel(mainViewModel: MainViewModel): ViewModel
}

ViewModelFactory:

@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 {
        val creator = viewModels[modelClass]
                ?: viewModels.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)
        }
    }
}

Класс приложения:

class MyCustomApplication : Application(), HasActivityInjector, HasSupportFragmentInjector {

    @Inject lateinit var activityInjector: DispatchingAndroidInjector<Activity>

    override fun onCreate() {
        super.onCreate()

        DaggerMainComponent
                .builder()
                .application(this)
                .build()
                .inject(this)
    }

    override fun activityInjector() = activityInjector
}

MainViewModel ( обратите внимание, что он расширяется от AndroidViewModel и требует контекст приложения ):

class MainViewModel @Inject constructor(app: Application, private val repository: MainRepository)
    : AndroidViewModel(app) {

MainActivity:

class MainActivity : BaseActivity() {

    @Inject
    internal lateinit var viewModelFactory: ViewModelProvider.Factory
    private lateinit var viewModel: MainViewModel

    override fun onCreate(savedState: Bundle?) {
        AndroidInjection.inject(this)
        super.onCreate(savedState)
        viewModel = ViewModelProviders.of(this,viewModelFactory).get(MainViewModel::class.java)

Ответы [ 2 ]

1 голос
/ 21 мая 2019

Я столкнулся с той же проблемой, комбинируя Android X и Kotlin version 1.3.0, Dagger не сможет создать MultiBindings. Для решения проблемы я просто следовал следующим шагам:

a) Обновление версии Kotlin до 1.3.31 в файле build.gradle:

dependencies {
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin: 1.3.31"
}

b) Очистить и перестроить проект, для этого выполнить в терминале следующую команду:

$ gradle clean build 

или при использовании упаковщика:

 $ ./gradlew clean build
0 голосов
/ 15 июля 2019

Я попытался обновить kotlin-gradle-plugin до 1.3.31, но у меня это не сработало.

Проведя некоторое время в Интернете, я нашел следующее решение, которое работает для меня.

Попробуйте добавить @JvmSuppressWildcards перед Provider<ViewModel>, как показано ниже:

@Singleton
@Provides
fun provideViewModelFactory(creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>): ViewModelFactory {
    return ViewModelFactory(creators)
}

И в ViewModelFactory.

class ViewModelFactory(private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>) :
        ViewModelProvider.Factory
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...