Dagger2:如果没有@Provides注释的方法,则无法提供ViewModel

时间:2019-01-28 10:06:05

标签: android kotlin dagger-2 androidx android-jetpack

我正在遵循Google GithubBrowserSample使用的体系结构。但是在构建项目时面临麻烦。

我已将项目迁移到AndroidX。我尝试了许多StackOverflow上可用的答案,但均未成功。 这是我在构建时遇到的构建异常:

e:/windows/Apps/Verifi/VerifiApp/app/build/tmp/kapt3/stubs/debug/com/verifi/di/component/AppComponent.java:11: error: [Dagger/MissingBinding] [dagger.android.AndroidInjector.inject(T)] 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 extends dagger.android.AndroidInjector<com.verifi.VerifiApp> {
                ^
      java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at
          com.verifi.viewmodel.AppViewModelFactory.<init>(creators)
      com.verifi.viewmodel.AppViewModelFactory is injected at
          com.verifi.ui.auth.AuthActivity.appViewModelFactory
      com.verifi.ui.auth.AuthActivity is injected at
          dagger.android.AndroidInjector.inject(T)
  component path: com.verifi.di.component.AppComponent → com.verifi.di.module.ActivityBindingModule_AuthActivity.AuthActivitySubcomponent

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:kaptDebugKotlin'.

VerifiApp.kt

class VerifiApp: Application(), HasActivityInjector {

    @Inject
    lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>

    override fun onCreate() {
        super.onCreate()

        if (BuildConfig.DEBUG) {
            Timber.plant(Timber.DebugTree())
        }

        AppInjector.init(this)
    }

    override fun activityInjector() = dispatchingAndroidInjector
}

AppComponent.kt

@Singleton
@Component(
    modules = [AndroidSupportInjectionModule::class,
        AppModule::class,
        ActivityBindingModule::class])
interface AppComponent: AndroidInjector<VerifiApp> {
    @Component.Builder
    interface Builder {

        @BindsInstance
        fun application(application: Application): Builder

        fun build(): AppComponent
    }

    override fun inject(verifiApp: VerifiApp)
}

AppModule.kt:

@Module(includes = [ViewModelBindingModule::class])
class AppModule {

    @Provides
    @Singleton
    internal fun provideContext(application: Application): Context = application

    @Provides
    @Singleton
    internal fun getRemoteSource(remoteDataManager: RemoteDataManager): IRemoteSource = remoteDataManager

    @Provides
    @Singleton
    internal fun provideDataManger(appDataManager: AppDataManager): IAppDataSource = appDataManager

    @Singleton
    @Provides
    fun provideVerifiService(): VerifiService {
        return Retrofit.Builder()
            .baseUrl("https://api.github.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(LiveDataCallAdapterFactory())
            .build()
            .create(VerifiService::class.java)
    }
}

ViewModelBindingModule:

@Suppress("unused")
@Module(includes = [AuthViewModelsBindingModule::class])
abstract class ViewModelBindingModule {

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

    @Binds
    @IntoMap
    @ViewModelKey(AuthViewModel::class)
    abstract fun bindAuthViewModel(authViewModel: AuthViewModel): AuthViewModel
}

任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:1)

abstract fun bindAuthViewModel(authViewModel: AuthViewModel): AuthViewModel

应该返回ViewModel而不是AuthViewModel

答案 1 :(得分:1)

当我将Java代码更改为kotlin形式时,它对我有用

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@MapKey
public @interface ViewModelKey {
    Class<? extends ViewModel> value();
}

收件人

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

并且来自


public class ViewModelProviderFactory implements ViewModelProvider.Factory {

    private static final String TAG = "ViewModelProviderFactor";

    private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;

    @Inject
    public ViewModelProviderFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
        this.creators = creators;
    }

    @Override
    public <T extends ViewModel> T create(Class<T> modelClass) {
        Provider<? extends ViewModel> creator = creators.get(modelClass);
        if (creator == null) { // if the viewmodel has not been created

            // loop through the allowable keys (aka allowed classes with the @ViewModelKey)
            for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : creators.entrySet()) {

                // if it's allowed, set the Provider<ViewModel>
                if (modelClass.isAssignableFrom(entry.getKey())) {
                    creator = entry.getValue();
                    break;
                }
            }
        }

        // if this is not one of the allowed keys, throw exception
        if (creator == null) {
            throw new IllegalArgumentException("unknown model class " + modelClass);
        }

        // return the Provider
        try {
            return (T) creator.get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

收件人

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

    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        val creator = viewModelsMap[modelClass] ?:
        viewModelsMap.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)
        }
    }

}

答案 2 :(得分:0)

它在Kotlin Dagger处理器中的问题 您应该将您的 ViewModelFactory ViewModelKey 转换为Java,因为它可以为我工作

相关问题