I am getting a IllegalStateException
when observing a LiveData from view model as state within Activity onCreate. Its complaining about missing lifecycle owner, however as per my understanding observeAsState() should take lifecycle of its owner, in this case the activity.
Below is the crash log:
java.lang.IllegalStateException: CompositionLocal LocalLifecycleOwner not present
at androidx.lifecycle.compose.LocalLifecycleOwnerKt$LocalLifecycleOwner$1.invoke(LocalLifecycleOwner.kt:26)
at androidx.lifecycle.compose.LocalLifecycleOwnerKt$LocalLifecycleOwner$1.invoke(LocalLifecycleOwner.kt:25)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at androidx.compose.runtime.LazyValueHolder.getCurrent(ValueHolders.kt:46)
at androidx.compose.runtime.LazyValueHolder.readValue(ValueHolders.kt:48)
at androidx.compose.runtime.CompositionLocalMapKt.read(CompositionLocalMap.kt:91)
at androidx.compose.runtime.ComposerImpl.consume(Composer.kt:2366)
at androidx.compose.runtime.livedata.LiveDataAdapterKt.observeAsState(LiveDataAdapter.kt:72)
at com.example.testblockers.MainActivityKt.MyApp(MainActivity.kt:57)
at com.example.testblockers.MainActivity$onCreate$1$1$1.invoke(MainActivity.kt:44)
at com.example.testblockers.MainActivity$onCreate$1$1$1.invoke(MainActivity.kt:43)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.material3.SurfaceKt$Surface$1.invoke(Surface.kt:129)
at androidx.compose.material3.SurfaceKt$Surface$1.invoke(Surface.kt:113)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:362)
at androidx.compose.material3.SurfaceKt.Surface-T9BRK9s(Surface.kt:110)
at com.example.testblockers.MainActivity$onCreate$1$1.invoke(MainActivity.kt:43)
at com.example.testblockers.MainActivity$onCreate$1$1.invoke(MainActivity.kt:42)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:362)
at androidx.compose.material3.TextKt.ProvideTextStyle(Text.kt:261)
at androidx.compose.material3.MaterialThemeKt$MaterialTheme$1.invoke(MaterialTheme.kt:81)
at androidx.compose.material3.MaterialThemeKt$MaterialTheme$1.invoke(MaterialTheme.kt:80)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:362)
at androidx.compose.material3.MaterialThemeKt.MaterialTheme(MaterialTheme.kt:73)
at com.example.testblockers.ui.theme.ThemeKt.TestBlockersTheme(Theme.kt:65)
at com.example.testblockers.MainActivity$onCreate$1.invoke(MainActivity.kt:42)
at com.example.testblockers.MainActivity$onCreate$1.invoke(MainActivity.kt:41)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.ui.platform.ComposeView.Content(ComposeView.android.kt:428)
at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:252)
at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:251)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:362)
at androidx.compose.ui.platform.CompositionLocalsKt.ProvideCommonCompositionLocals(CompositionLocals.kt:186)
Here is the View Model:
class MainViewModel : ViewModel() {
private val _counterLiveData = MutableLiveData<Int>()
// Expose LiveData as immutable
val counterLiveData: LiveData<Int>
get() = _counterLiveData
init {
// Initialize LiveData with default value
_counterLiveData.value = 0
}
fun incrementCounter() {
_counterLiveData.value = (_counterLiveData.value ?: 0) + 1
}
}
Here is the Activity where I am observing the Live Data:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
// Initialize ViewModel
val viewModel: MainViewModel = viewModel()
TestBlockersTheme {
Surface(color = MaterialTheme.colorScheme.background) {
MyApp(viewModel)
}
}
}
}
}
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyApp(viewModel: MainViewModel) {
// Observe the counterLiveData from the ViewModel
val counterState by viewModel.counterLiveData.observeAsState(initial = 0)
Scaffold(
topBar = {
TopAppBar(
title = { Text("Counter App") }
)
},
content = {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Counter: $counterState",
style = MaterialTheme.typography.bodyMedium
)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = { viewModel.incrementCounter() }) {
Text("Increment")
}
}
}
)
}
Below is the gradle dependencies:
dependencies {
implementation("androidx.core:core-ktx:1.13.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.activity:activity-compose:1.9.0")
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
// jsoup HTML parser library @ https://jsoup.org/
implementation("org.jsoup:jsoup:1.17.2")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
implementation("androidx.compose.runtime:runtime-livedata:1.7.0-alpha07")
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.7.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
}
Is anyone familiar with this issue?
You mix compose artifacts from different versions that are not compatible.
Although you use the Compose BOM 2023.03.00
, you explicitly specify version 1.7.0-alpha07
for androidx.compose.runtime:runtime-livedata
. Just remove the version for runtime-livedata and it will fall back to the version determined by the BOM which will be 1.4.0
and your code will work again.