Kotlin集成Dagger 2.15遇ViewModel注入错误:需@Provides注解方法
我来帮你搞定这个Dagger和ViewModel的注入坑!你遇到的这个编译错误,核心是Dagger找不到提供Map<java.lang.Class<? extends android.arch.lifecycle.ViewModel>,? extends javax.inject.Provider<android.arch.lifecycle.ViewModel>>的@Provides方法——这在ViewModel注入场景里是非常典型的疏漏,咱们一步步来修复:
1. 补全ViewModel绑定的核心注解和Module
首先你需要一个自定义的@ViewModelKey注解,用来标记ViewModel类作为Map的key:
@MapKey @Target(AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) annotation class ViewModelKey(val value: KClass<out ViewModel>)
然后创建一个抽象的ViewModelModule,用@Binds + @IntoMap + @ViewModelKey的组合,把每个ViewModel绑定到Dagger的映射表中:
@Module abstract class ViewModelModule { // 替换成你项目里的ViewModel类,比如RecipeViewModel @Binds @IntoMap @ViewModelKey(RecipeViewModel::class) abstract fun bindRecipeViewModel(viewModel: RecipeViewModel): ViewModel // 如果有其他ViewModel,同样添加对应的绑定方法 }
⚠️ 关键注意:这里的Module必须是抽象类,@Binds方法也要是抽象的,而且你的ViewModel构造函数必须加上@Inject注解,比如:
class RecipeViewModel @Inject constructor( private val recipeRepository: RecipeRepository ) : ViewModel() { // 你的ViewModel业务逻辑 }
2. 实现Dagger专属的ViewModelFactory
接下来需要一个ViewModelFactory,让Dagger把刚才的ViewModel映射表注入进来,供Activity/Fragment获取ViewModel:
class DaggerViewModelFactory @Inject constructor( private val viewModelMap: MutableMap<Class<out ViewModel>, Provider<ViewModel>> ) : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>): T { val viewModelProvider = viewModelMap[modelClass] ?: throw IllegalArgumentException("找不到对应的ViewModel类: $modelClass") return viewModelProvider.get() as T } }
3. 关联ViewModelModule和Factory到Dagger Component
确保你的AppComponent(或者对应的ActivityComponent)包含了ViewModelModule,并且暴露ViewModelFactory的注入入口:
@Singleton @Component(modules = [ViewModelModule::class, AndroidSupportInjectionModule::class, /*其他你的业务Module*/]) interface AppComponent { fun inject(app: YourApplication) // 暴露ViewModelFactory,供Activity注入使用 fun viewModelFactory(): DaggerViewModelFactory }
如果是用@ContributesAndroidInjector的方式管理Activity注入,可以在Activity的子Module里提供Factory:
@Module class MainActivityModule { @Provides fun provideViewModelFactory(factory: DaggerViewModelFactory): ViewModelProvider.Factory { return factory } }
4. 在Activity中注入并使用ViewModel
最后,在你的Activity里注入ViewModelFactory,并用它获取ViewModel:
class MainActivity : AppCompatActivity(), HasAndroidInjector { @Inject lateinit var viewModelFactory: ViewModelProvider.Factory private lateinit var recipeViewModel: RecipeViewModel override fun onCreate(savedInstanceState: Bundle?) { AndroidInjection.inject(this) super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 通过Dagger的Factory获取ViewModel recipeViewModel = ViewModelProvider(this, viewModelFactory)[RecipeViewModel::class.java] } // 实现HasAndroidInjector接口的要求 @Inject lateinit var androidInjector: DispatchingAndroidInjector<Any> override fun androidInjector(): AndroidInjector<Any> = androidInjector }
5. 检查依赖和注解处理器配置
最后确认你的Module级build.gradle里的依赖配置正确,尤其是kapt注解处理器:
// Dagger相关依赖 implementation 'com.google.dagger:dagger:2.15' implementation 'com.google.dagger:dagger-android:2.15' implementation 'com.google.dagger:dagger-android-support:2.15' kapt 'com.google.dagger:dagger-compiler:2.15' kapt 'com.google.dagger:dagger-android-processor:2.15' // ViewModel相关依赖(对应你用的旧版Architecture Components) implementation 'android.arch.lifecycle:extensions:1.1.1' implementation 'android.arch.lifecycle:viewmodel-ktx:1.1.1'
⚠️ 注意:因为你用的是android.arch.lifecycle(旧版Android Architecture Components),请不要混用AndroidX的ViewModel依赖,否则会出现版本冲突。
按照这些步骤调整后,重新编译项目,那个缺少@Provides方法的错误应该就会消失了!
内容的提问来源于stack exchange,提问作者Ramprasad Ranganathan

