Tiamat icon indicating copy to clipboard operation
Tiamat copied to clipboard

Tiamat with HiltViewModel stopped working with version 2.0.0

Open 64ArthurAraujo opened this issue 1 month ago • 6 comments

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 avatar Nov 27 '25 01:11 64ArthurAraujo

@64ArthurAraujo Thanks for reaching, will take a look onto this.

vkatz avatar Nov 27 '25 07:11 vkatz

@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

vkatz avatar Nov 27 '25 07:11 vkatz

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

64ArthurAraujo avatar Nov 27 '25 09:11 64ArthurAraujo

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

vkatz avatar Nov 28 '25 10:11 vkatz

@64ArthurAraujo

Image

Some basic fix is ready, need to test it before release...

vkatz avatar Nov 28 '25 11:11 vkatz

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
    }

vkatz avatar Nov 28 '25 11:11 vkatz