Я пытаюсь разделить одну ViewModel между двумя действиями. Я получаю следующую ошибку ViewModel cannot be provided without an @Inject constructor or an @Provides-annotated method
. Основная цель, которую я пытаюсь достичь sh, - использовать общую ViewModel между различными действиями, в моем случае LoginActivity
и SampleActivity
. Лучший способ сделать это - использовать ViewModelFactory. Поэтому я использую кинжал для внедрения ViewModelFactory в обе активности, в настоящее время я застрял на вышеуказанной ошибке.
Вот файл 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]
Любая помощь приветствуется!