代码之家  ›  专栏  ›  技术社区  ›  Ankit Mehta

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

  •  0
  • Ankit Mehta  · 技术社区  · 6 年前

    我遵循 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'.
    

    验证app.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
    }
    

    :

    @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)
        }
    }
    

    :

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

    任何帮助都将不胜感激。

    1 回复  |  直到 6 年前
        1
  •  10
  •   Blackbelt    6 年前

    abstract fun bindAuthViewModel(authViewModel: AuthViewModel): AuthViewModel

    应该会返回一个 ViewModel AuthViewModel

        2
  •  3
  •   Abd-Elwahab Zayed    4 年前

    当我将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)
            }
        }
    
    }
    
        3
  •  0
  •   Suresh kumar    5 年前

    它在Kotlin匕首处理器中的问题 ViewModelFactory 因为它对我有用