Reputation: 55
Trying to create a view model in a fragment by providing the factory with a dagger but app crashes with error. Move injection to another lifecycle doesn't work
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.bigproject.planyourlife, PID: 13934
kotlin.UninitializedPropertyAccessException: lateinit property factory has not been initialized
at com.bigproject.planyourlife.view.SignupFragment.getFactory(SignupFragment.kt:27)
ViewModel
class SignupViewModel(private val service: AuthService) : ViewModel() {
private var email: String = ""
private var password: String = ""
private val _uiState = MutableStateFlow<SignupState>(SignupState.Success(null))
val uiState: StateFlow<SignupState> = _uiState
@Suppress("UNCHECKED_CAST")
class Factory @Inject constructor(
private val service: AuthService
) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
require(modelClass == SignupViewModel::class)
return SignupViewModel(service) as T
}
}
Fragment
class SignupFragment : Fragment(R.layout.signup_page) {
private val binding by viewBinding(SignupPageBinding::bind)
private val signupViewModel: SignupViewModel by viewModels {
factory
}
@Inject
lateinit var factory: SignupViewModel.Factory
override fun onAttach(context: Context) {
context.appComponent.inject(this)
super.onAttach(context)
}
}
Upvotes: 1
Views: 5229
Reputation: 2421
First, create a module for your ViewModelFactory. This is important for you to provide ViewModelFactory for dagger.
ViewModelModule.kt
@Module
abstract class ViewModelModule {
@Binds
abstract fun provideViewModelFactory(factory: Factory): ViewModelProvider.Factory
// Binds your viewmodel in here.
}
Next, you need to include that module in your component. Specifically here is AppComponent
.
AppComponent.kt
@Singleton
@Component(modules = [ViewModelModule::class, YourFragmentModule::class, YourActivityModule::class, ...])
interface AppComponent {
@Component.Factory
abstract class Factory : AndroidInjector.Factory<YourApplication>
}
And now, viewModelFactory
is ready for you to inject into your Fragment, Activity, ....
YourFragment.kt
class YourFragment: Fragment() {
@Inject
lateinit var viewModelFactory: Factory
}
Upvotes: 1