Tiamat with HiltViewModel stopped working with version 2.0.0
In my app i use Hilt for DI which worked flawlessly in 1.5.0, but with the upgrade to tiamat 2.0.0 it now crashes when trying to instantiate a ViewModel with the following error:
FATAL EXCEPTION: main
Process: cc.wordview.app, PID: 6521
java.lang.RuntimeException: Cannot create an instance of class cc.wordview.app.ui.activities.auth.viewmodel.login.LoginViewModel
at androidx.lifecycle.viewmodel.internal.JvmViewModelProviders.createViewModel(JvmViewModelProviders.kt:42)
at androidx.lifecycle.viewmodel.internal.DefaultViewModelProviderFactory.create(DefaultViewModelProviderFactory.jvm.kt:26)
at androidx.lifecycle.viewmodel.internal.ViewModelProviderImpl_androidKt.createViewModel(ViewModelProviderImpl.android.kt:35)
at androidx.lifecycle.viewmodel.internal.ViewModelProviderImpl.getViewModel$lifecycle_viewmodel(ViewModelProviderImpl.kt:59)
at androidx.lifecycle.viewmodel.internal.ViewModelProviderImpl.getViewModel$lifecycle_viewmodel$default(ViewModelProviderImpl.kt:43)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.android.kt:90)
at androidx.lifecycle.viewmodel.compose.ViewModelKt__ViewModelKt.get(ViewModel.kt:172)
at androidx.lifecycle.viewmodel.compose.ViewModelKt.get(Unknown Source:1)
at androidx.lifecycle.viewmodel.compose.ViewModelKt__ViewModelKt.viewModel(ViewModel.kt:106)
at androidx.lifecycle.viewmodel.compose.ViewModelKt.viewModel(Unknown Source:1)
at cc.wordview.app.ui.activities.auth.composables.ComposableSingletons$LoginKt.lambda_1761666280$lambda$0(Login.kt:171)
at cc.wordview.app.ui.activities.auth.composables.ComposableSingletons$LoginKt.$r8$lambda$Ftxq6Rv5SgqIRO81GhuEHr4ghrY(Unknown Source:0)
at cc.wordview.app.ui.activities.auth.composables.ComposableSingletons$LoginKt$$ExternalSyntheticLambda1.invoke(D8$$SyntheticClass:0)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:130)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:51)
at com.composegears.tiamat.compose.ComposeNavDestination.Content$tiamat(NavDestination.kt:53)
at com.composegears.tiamat.compose.ComposableNavEntryKt.NavEntryContent$lambda$0$0(ComposableNavEntry.kt:47)
at com.composegears.tiamat.compose.ComposableNavEntryKt.$r8$lambda$IJD7OLvdl4i5NLO5XaiclFFFiWE(Unknown Source:0)
at com.composegears.tiamat.compose.ComposableNavEntryKt$$ExternalSyntheticLambda0.invoke(D8$$SyntheticClass:0)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:121)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:51)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:370)
at com.composegears.tiamat.compose.ComposableNavEntryKt.NavEntryContent(ComposableNavEntry.kt:30)
at com.composegears.tiamat.compose.ComposableNavigationKt.NavigationScene$lambda$6$0$0(ComposableNavigation.kt:271)
at com.composegears.tiamat.compose.ComposableNavigationKt.$r8$lambda$-Z6rJKZ9BzjBsuYbUlV1UidAhbM(Unknown Source:0)
at com.composegears.tiamat.compose.ComposableNavigationKt$$ExternalSyntheticLambda0.invoke(D8$$SyntheticClass:0)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:130)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:51)
at com.composegears.tiamat.compose.NavigationSceneScope.EntryContent(NavigationSceneScope.kt:39)
at com.composegears.tiamat.compose.ComposableNavigationKt.Navigation$lambda$4$13$0(ComposableNavigation.kt:157)
at com.composegears.tiamat.compose.ComposableNavigationKt.$r8$lambda$THN_hTq6eobUSxCnOjs5ZKhKOks(Unknown Source:0)
at com.composegears.tiamat.compose.ComposableNavigationKt$$ExternalSyntheticLambda15.invoke(D8$$SyntheticClass:0)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:121)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:51)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:390)
at com.composegears.tiamat.compose.ComposableNavigationKt.Navigation$lambda$4$13(ComposableNavigation.kt:153)
I have read the migration guide and i think its probably due to point 7, but im not sure because i dont use SavedStateHandle, here is my ViewModel:
@HiltViewModel
class LoginViewModel @Inject constructor(
private val loginRepository: LoginRepository,
@ApplicationContext private val appContext: Context
) : ViewModel() {
private val _isLoading = MutableStateFlow(false)
val isLoading = _isLoading.asStateFlow()
private var _snackBarMessage = MutableSharedFlow<String>()
val snackBarMessage = _snackBarMessage.asSharedFlow()
...
}
@64ArthurAraujo Thanks for reaching, will take a look onto this.
@64ArthurAraujo
Looks like you'r using viewModel: LoginViewModel= viewModel(),
can you try to use val viewModel = hiltViewModel<LoginViewModel>() instead? (at least in order to verify)
Will check this casess too
I tested 3 cases, val viewModel = hiltViewModel<LoginViewModel>(), val viewModel: LoginViewModel = hiltViewModel(), and val viewModel: LoginViewModel = viewModel() all of them failed with the same exception as above
Thx for info, going to focus on this issue. Planing fix would be either in the intermediate release (2.2.0-alpha01) together with compose 1.10.?-betha0? or else 2.2.0+ compose 1.10.0 release
@64ArthurAraujo
Some basic fix is ready, need to test it before release...
WIP:
Bug-src
Hilt rely on ModelStoreOwner is HasDefaultViewModelProviderFactory installed by one of hilts annotations for activity/fragment
Nav3 solve it manually by this: https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:lifecycle/lifecycle-viewmodel-navigation3/src/commonMain/kotlin/androidx/lifecycle/viewmodel/navigation3/ViewModelStoreNavEntryDecorator.kt;drc=94a24fe852d2e840c246bfe40f201a5272da9f8d;l=104
We: redirect this interface to host with adjusted ViewModelStoreOwner
return remember(entry) {
if (parentViewModelStoreOwner is HasDefaultViewModelProviderFactory) {
object : ViewModelStoreOwner,
HasDefaultViewModelProviderFactory by parentViewModelStoreOwner {
override val viewModelStore: ViewModelStore = entry.viewModelStore
}
} else entry
}