I want to provide viewmodel through dagger, So I was using a ViewModelProviderFactory which has the map multibinding. Here is the code for ViewModelProviderFactory.kt:
@Singleton
class ViewModelProviderFactory @Inject constructor(private val viewModels: MutableMap<Class<out ViewModel>, Provider<ViewModel>>) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T = viewModels[modelClass]?.get() as T
}
And this is my ViewModelFactoryModule.kt :
@Module
abstract class ViewModelFactoryModule {
@Binds
abstract fun bindViewModelFactory(providerFactory: ViewModelProviderFactory) : ViewModelProvider.Factory
}
This is my ViewModelKey.kt :
@Documented
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value : KClass<out ViewModel>) {
}
I want to add AuthViewModel to my activity named Login, here is my AuthViewModelModule.kt :
@Module
abstract class AuthViewModelModule {
@Binds
@IntoMap
@ViewModelKey(AuthViewModel::class)
abstract fun bindAuthViewModel(viewModel : AuthViewModel) : ViewModel
}
and this is Login.kt :
class Login : AppCompatActivity() {
@Inject
lateinit var providerFactory : ViewModelProviderFactory
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val api = Api.instance
val repository = UserRepository(api)
val factory = AuthViewModelFactory(repository)
val binding: ActivityLoginBinding =
DataBindingUtil.setContentView(this, R.layout.activity_login)
val viewModel = ViewModelProvider(this, providerFactory).get(AuthViewModel::class.java)
binding.viewmodel = viewModel
}
}
This is my AppComponent.kt
@Singleton
@Component(
modules = [
AndroidSupportInjectionModule::class,
ActivityBuildersModule::class,
AppModule::class,
ViewModelFactoryModule::class
]
)
interface AppComponent : AndroidInjector<BaseApplication> {
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: Application) : Builder
fun build() : AppComponent
}
}
And my ActivityBuildersModule.kt :
@Module
abstract class ActivityBuildersModule {
@ContributesAndroidInjector(
modules = [AuthViewModelModule::class]
)
abstract fun contributeLogin() : Login
}
Here is my AppModule.kt :
@Module
class AppModule {
@Module
companion object
{
@Provides
@JvmStatic
fun providesAppNull(application: Application) : Boolean = application == null
}
}
}
This is my AuthViewModel :
class AuthViewModel @Inject constructor(
) : ViewModel() {
var name: String? = null
var email: String? = null
var password: String? = null
var password_confirm: String? = null
var authListener: AuthListener? = null
fun onSignUpButtonClicked(view: View) {
authListener?.onStarted()
val mContext = view.context
if (name.isNullOrEmpty() || email.isNullOrEmpty() || password.isNullOrEmpty() || password_confirm.isNullOrEmpty()) {
authListener?.onFailure("Invalid email or password!")
return
} else if (!password.equals(password_confirm)) {
authListener?.onFailure("Passwords do not match!!!")
return
} else {
Log.d("AuthViewModel", "doing something")
}
}
}
Instead injecting all of these I'm getting error for not providing, this is the error I'm getting right now:
java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> cannot be provided without an @Provides-annotated method.
java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at
com.kreeti.gogal.viewmodels.ViewModelProviderFactory(viewModels)
com.kreeti.gogal.viewmodels.ViewModelProviderFactory is injected at
com.kreeti.gogal.di.ViewModelFactoryModule.bindViewModelFactory(providerFactory)
androidx.lifecycle.ViewModelProvider.Factory is injected at
com.kreeti.gogal.ui.auth.Login.providerFactory
com.kreeti.gogal.ui.auth.Login is injected at