我正在尝试在两个活动之间共享一个ViewModel。我收到以下错误ViewModel cannot be provided without an @Inject constructor or an @Provides-annotated method
。我要实现的主要目标是在不同的活动之间使用共享的ViewModel,在我的情况下为LoginActivity
和SampleActivity
。最好的方法是使用ViewModelFactory。因此,我使用匕首将ViewModelFactory注入到两个Activity中,当前我陷入了上述错误。
这里是build.gadle
文件:
implementation("com.google.dagger:dagger:2.26")
implementation("com.google.dagger:dagger-android-support:2.26")
implementation("com.google.dagger:dagger-android:2.26")
kapt "com.google.dagger:dagger-android-processor:2.26"
kapt "com.google.dagger:dagger-compiler:2.26"
这里是ActivityModule.kt
:
@Module
abstract class ActivityModule {
@ContributesAndroidInjector
abstract fun contributeLoginActivity(): LoginActivity
@ContributesAndroidInjector
abstract fun contributeSampleActivity(): SampleActivity
}
这里是AppComponent.kt
:
@Singleton
@Component(
modules = [
AppModule::class,
AndroidInjectionModule::class,
ViewModelModule::class,
ActivityModule::class
]
)
interface AppComponent {
fun inject(app: MainApplication)
@Component.Factory
interface Factory {
fun create(@BindsInstance context: Context): AppComponent
}
}
这里是AppModule.kt
@Module(includes = [ViewModelModule::class])
class AppModule {
}
ViewModelKey.kt
:
@Suppress("DEPRECATED_JAVA_ANNOTATION")
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)
ViewModelModule.kt
:
@Module
abstract class ViewModelModule {
@Binds
@IntoMap
@ViewModelKey(MainViewModel::class) // PROVIDE YOUR OWN MODELS HERE
internal abstract fun bindMainViewModel(mainViewModel: MainViewModel): ViewModel
@Binds
internal abstract fun bindViewModelProviderFactory(factory: ViewModelProviderFactory): ViewModelProvider.Factory
}
这里是MainApplication.kt
class MainApplication: Application(), HasAndroidInjector {
@Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
override fun onCreate() {
super.onCreate()
DaggerAppComponent.factory().create(this).inject(this)
}
override fun androidInjector() = dispatchingAndroidInjector
}
LoginActivity.kt
class LoginActivity : DaggerAppCompatActivity() {
@Inject lateinit var modelFactory: ViewModelProvider.Factory
lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
val button: Button = findViewById(R.id.button)
button.setOnClickListener { onButtonClick() }
val label: TextView = findViewById(R.id.counter)
viewModel = ViewModelProvider(this, modelFactory).get(MainViewModel::class.java)
println("stack: ${viewModel.hashCode()}")
viewModel.userLogin.observe(this, Observer{ user ->
print("Debug: ${user}")
if(user != null){
label.text = user.user.name
redirectToLogin()
}
})
}
fun onButtonClick(){
var username: EditText = findViewById(R.id.username)
var password: EditText = findViewById(R.id.password)
println(username.text.toString())
println(password.text.toString())
viewModel.setUser(username.text.toString(), password.text.toString())
}
fun redirectToLogin(){
println("Login done!")
val intent = Intent(this, SampleActivity::class.java)
intent.putExtra("extra", viewModel.userLogin.value)
startActivity(intent)
}
}
SampleActivity.kt
class SampleActivity : DaggerAppCompatActivity() {
lateinit var viewModel: MainViewModel
@Inject lateinit var modelFactory: ViewModelProvider.Factory
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sample)
val loggedInUser: LoggedInUser? = intent.getParcelableExtra("extra")
// println("extra: $loggedInUser")
viewModel = ViewModelProvider(this, modelFactory).get(MainViewModel::class.java)
println("stack: ${viewModel.hashCode()}")
println(" $ WORKS: ${viewModel.userLogin.value?.user?.name}")
}
}
我似乎找不到问题,这是整个错误堆栈:
public abstract interface AppComponent {
^
company.MyApp.ViewModels.MainViewModel is injected at
company.MyApp.di.ViewModelModule.bindMainViewModel$app_debug(mainViewModel)
java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at
company.MyApp.ViewModels.ViewModelProviderFactory(creators)
company.MyApp.ViewModels.ViewModelProviderFactory is injected at
company.MyApp.di.ViewModelModule.bindViewModelProviderFactory$app_debug(factory)
androidx.lifecycle.ViewModelProvider.Factory is injected at
company.MyApp.LoginActivity.modelFactory
company.MyApp.LoginActivity is injected at
dagger.android.AndroidInjector.inject(T) [company.MyApp.di.AppComponent → company.MyApp.di.ActivityModule_ContributeLoginActivity.LoginActivitySubcomponent]
The following other entry points also depend on it:
dagger.android.AndroidInjector.inject(T) [company.MyApp.di.AppComponent → company.MyApp.di.ActivityModule_ContributeSampleActivity.SampleActivitySubcomponent]
感谢您的任何帮助!
将ViewModel的@Provides注释方法添加到AppModule:
@Module(includes = [ViewModelModule::class])
class AppModule {
@Provides
@Named("mainViewModel")
fun provideMainViewModel(): MainViewModel =
MainViewModel()
}
如果您的ViewModel使用UseCase,则也需要在此处注入它们,例如:
@Module(includes = [ViewModelModule::class])
class AppModule {
@Provides
@Named("mainViewModel")
fun provideMainViewModel(): MainViewModel =
MainViewModel(
provideExampleUseCase()
)
@Provides
@Named("exampleUseCase")
fun provideExampleUseCase(): ExampleUseCase =
ExampleUseCase()
}
这是ViewModel的外观:
class MainViewModel
@Inject constructor(
private val exampleUseCase: ExampleUseCase,
) : ViewModel() {
//........
}
请注意,如果您的UseCase需要注入存储库,则需要将其注入到UseCase中,就像将UseCase注入到ViewModel中一样。