androidandroid-jetpack-compose

App Crashing With ViewModel Android Jetpack Compose


With the configuration below the app is crashing when the @Composable view calling a ViewModel opens. Below is the error message as well. I'm not sure if it's the configuration of the database in the ViewModel. I originally wanted to create an instance of the database in the ViewModel and pass context to the ViewModel but I read that isn't best practice.

ViewModel:

class DataModel(): ViewModel() {
    lateinit var database: AppDatabase

    fun setDatabase(context: Context) {
        database = Room.databaseBuilder(
            context,
            AppDatabase::class.java, "database"
        ).build()
    }

     val data: StateFlow<List<Data>> = flow {
         emit(database.dataDao().getAll())
     } as StateFlow<List<Data>>

    fun addData(data: Data) {
        viewModelScope.launch {
            database.dataDao().insert(data)
        }
    }
}

RoomDatabase:

@Database(entities = [Data::class], version = 1)
@TypeConverters(BooleanArrayConverter::class)
abstract class AppDatabase: RoomDatabase() {
    abstract fun data(): DataDao
}

@Dao Interface:

@Dao
interface DataDao {
    @Query("SELECT * FROM data")
    suspend fun getAll(): List<Data>

    @Insert
    suspend fun insert(vararg data: Data)
}

@Composable View:

fun View(
    dataModel: DataModel = viewModel(),
) {
     var context = LocalContext.current

     Button(
         onClick = {
            dataModel.setDatabase(context)
         },
    ) {
        Text("Button")
    }
}

Error:

FATAL EXCEPTION: main
                                                                                                        Process: com.example.app, PID: 12733
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:603)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:932)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:932) 
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
at androidx.lifecycle.viewmodel.internal.JvmViewModelProviders.createViewModel(JvmViewModelProviders.kt:38)
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.android.kt:185)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.android.kt:309)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.android.kt:269)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.android.kt:142)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.android.kt:112)
at androidx.lifecycle.viewmodel.ViewModelProviderImpl_androidKt.createViewModel(ViewModelProviderImpl.android.kt:34)
at androidx.lifecycle.viewmodel.ViewModelProviderImpl.getViewModel$lifecycle_viewmodel_release(ViewModelProviderImpl.kt:60)
at androidx.lifecycle.viewmodel.ViewModelProviderImpl.getViewModel$lifecycle_viewmodel_release$default(ViewModelProviderImpl.kt:43)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.android.kt:92)
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 com.example.app.View.NewJournalEntrySheet(View.kt:174)
at com.example.app.ComposableSingletons$ViewKt$lambda-1$1.invoke(JournalEntryScreen.kt:45)
at com.example.app.ComposableSingletons$ViewKt$lambda-1$1.invoke(JournalEntryScreen.kt:44)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:130)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:51)
at androidx.compose.material3.ModalBottomSheetKt$ModalBottomSheetContent$7.invoke(ModalBottomSheet.kt:341)
at androidx.compose.material3.ModalBottomSheetKt$ModalBottomSheetContent$7.invoke(ModalBottomSheet.kt:289)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:121)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:51)
at androidx.compose.material3.SurfaceKt$Surface$1.invoke(Surface.kt:126)
at androidx.compose.material3.SurfaceKt$Surface$1.invoke(Surface.kt:108)
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:364)
at androidx.compose.material3.SurfaceKt.Surface-T9BRK9s(Surface.kt:105)
at androidx.compose.material3.ModalBottomSheetKt.ModalBottomSheetContent-IQkwcL4(ModalBottomSheet.kt:218)
at androidx.compose.material3.ModalBottomSheetKt$ModalBottomSheet$3.invoke(ModalBottomSheet.kt:175)
at androidx.compose.material3.ModalBottomSheetKt$ModalBottomSheet$3.invoke(ModalBottomSheet.kt:168)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:121)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:51)
    2025-07-07 12:19:17.612 12733-12733 AndroidRuntime          com.example.peaceofmind              E      at androidx.compose.material3.ModalBottomSheet_androidKt$ModalBottomSheetDialog$dialog$1$1$1.invoke(ModalBottomSheet.android.kt:300)
at androidx.compose.material3.ModalBottomSheet_androidKt$ModalBottomSheetDialog$dialog$1$1$1.invoke(ModalBottomSheet.android.kt:296)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:121)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:51)
at androidx.compose.material3.ModalBottomSheetDialogLayout.Content(ModalBottomSheet.android.kt:354)
at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:250)
at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:250)
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:364)
at androidx.compose.ui.platform.CompositionLocalsKt.ProvideCommonCompositionLocals(CompositionLocals.kt:216)
at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(AndroidCompositionLocals.android.kt:122)
at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(AndroidCompositionLocals.android.kt:121)
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:364)
at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt.ProvideAndroidCompositionLocals(AndroidCompositionLocals.android.kt:110)
at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$3.invoke(Wrapper.android.kt:140)
at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$3.invoke(Wrapper.android.kt:139)
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:384)
at androidx.compose.ui.platform.WrappedComposition$setContent$1$1.invoke(Wrapper.android.kt:139)
at androidx.compose.ui.platform.WrappedComposition$setContent$1$1.invoke(Wrapper.android.kt:123)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:121)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:51)
at androidx.compose.runtime.internal.Utils_jvmKt.invokeComposable(Utils.jvm.kt:27)
at androidx.compose.runtime.ComposerImpl.doCompose-aFTiNEg(Composer.kt:3694)
at androidx.compose.runtime.ComposerImpl.composeContent--ZbOJvo$runtime_release(Composer.kt:3616)
at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:792)
at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Recomposer.kt:1132)
at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime_release(Composer.kt:4034)
at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime_release(Composer.kt:4034)
at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime_release(Composer.kt:4034)
at androidx.compose.runtime.CompositionImpl.composeInitial(Composition.kt:677)
at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:616)
at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:123)
at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:114)
at androidx.compose.ui.platform.AndroidComposeView.setOnViewTreeOwnersAvailable(AndroidComposeView.android.kt:1963)
    2025-07-07 12:19:17.613 12733-12733 AndroidRuntime          com.example.app              E      at androidx.compose.ui.platform.WrappedComposition.setContent(Wrapper.android.kt:114)
at androidx.compose.ui.platform.WrappedComposition.onStateChanged(Wrapper.android.kt:168)
at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.jvm.kt:313)
at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.jvm.kt:191)
at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:121)
at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:114)
at androidx.compose.ui.platform.AndroidComposeView.onAttachedToWindow(AndroidComposeView.android.kt:2042)
at android.view.View.dispatchAttachedToWindow(View.java:23105)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3520)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3527)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3527)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3527)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3527)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3618)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:3077)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:10644)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1570)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1579)
at android.view.Choreographer.doCallbacks(Choreographer.java:1179)
at android.view.Choreographer.doFrame(Choreographer.java:1108)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1553)
at android.os.Handler.handleCallback(Handler.java:995)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loopOnce(Looper.java:248)
at android.os.Looper.loop(Looper.java:338)
at android.app.ActivityThread.main(ActivityThread.java:9067)                                                                                                        ... 3 more
Caused by: java.lang.ClassCastException: kotlinx.coroutines.flow.SafeFlow cannot be cast to kotlinx.coroutines.flow.StateFlow
at DataModel.<init>(Data.kt:29)
                                                                                                            ... 104 more

Solution

  • This casting you are doing here is the problem

    val data: StateFlow<List<Data>> = flow {
         emit(database.dataDao().getAll())
     } as StateFlow<List<Data>>
    

    You cannot cast a Flow directly to a StateFlow

    You can either do this

    suspend fun getData() {
        data = flow {
            emit(database.dataDao().getAll())
        }.stateIn(viewModelScope)
    }
    

    or a better more typical approach would be

    private val _mutableDataFlow: MutableStateFlow<List<Data>> = MutableStateFlow<List<Data>>(mutableListOf())
    val data: StateFlow<List<Data>> = _mutableCodeFlow.asStateFlow()
    
    fun getData() {
        _mutableDataFlow.value = database.dataDao().getAll()
    }