Dagger2:如果没有 @Provides-annotated 方法,就无法提供 ViewModel
Posted
技术标签:
【中文标题】Dagger2:如果没有 @Provides-annotated 方法,就无法提供 ViewModel【英文标题】:Dagger2: ViewModel cannot be provided without an @Provides-annotated method 【发布时间】:2019-06-21 07:31:16 【问题描述】:我正在遵循 Google 使用的 GithubBrowserSample 架构。但是在建设项目时遇到了麻烦。
我已将项目迁移到 androidX。我在 *** 上尝试了许多可用的答案,但没有成功。 这是我在构建时遇到的构建异常:
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
任何帮助将不胜感激。
【问题讨论】:
【参考方案1】:abstract fun bindAuthViewModel(authViewModel: AuthViewModel): AuthViewModel
应该返回 ViewModel
而不是 AuthViewModel
【讨论】:
请查看***.com/questions/55669810/…【参考方案2】:当我将 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)
【讨论】:
仅将 @JvmSuppressWildcards 添加到 Provider它在 Kotlin Dagger 处理器中的问题 您应该将您的 ViewModelFactory 和 ViewModelKey 转换为 Java,因为它对我有用
【讨论】:
以上是关于Dagger2:如果没有 @Provides-annotated 方法,就无法提供 ViewModel的主要内容,如果未能解决你的问题,请参考以下文章
没有Dagger2的Android Kotlin MVVM结构
Kotlin + Dagger2:不能在没有 @Inject 构造函数或 @Provides- 或 @Produces-annotated 方法的情况下提供