Android Studio Chipmunk 2021.2.1;
Compose Version = '1.1.1';
Gradle Version 7.4.2;
Kotlin 1.6.10;
Up to one point, everything was working. Then this error appeared and the preview stopped working when I try to call "LocalContext.current" and make "context.applicationContext as Application" both in this project and in another one. Where it used to work with "LocalContext.current"
Tried on different versions of Compouse, kotlin, gradle.
java.lang.ClassCastException: class com.android.layoutlib.bridge.android.BridgeContext cannot be cast to class android.app.Application (com.android.layoutlib.bridge.android.BridgeContext and android.app.Application are in unnamed module of loader com.intellij.ide.plugins.cl.PluginClassLoader @3a848149) at com.client.personalfinance.screens.ComposableSingletons$AccountScreenKt$lambda-2$1.invoke(AccountScreen.kt:136) at com.client.personalfinance.screens.ComposableSingletons$AccountScreenKt$lambda-2$1.invoke(AccountScreen.kt:133) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.material.MaterialTheme_androidKt.PlatformMaterialTheme(MaterialTheme.android.kt:23) at androidx.compose.material.MaterialThemeKt$MaterialTheme$1$1.invoke(MaterialTheme.kt:82) at androidx.compose.material.MaterialThemeKt$MaterialTheme$1$1.invoke(MaterialTheme.kt:81) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228) at androidx.compose.material.TextKt.ProvideTextStyle(Text.kt:265
@Preview(showBackground = true) @Composable fun PrevAccountScreen() {
val context = LocalContext.current
val mViewModel: MainViewModel =
viewModel(factory = MainVeiwModelFactory(context.applicationContext as Application))
AccountScreen(navController = rememberNavController(), viewModel = mViewModel)
}
CodePudding user response:
This is a wrong line
viewModel(factory = MainVeiwModelFactory(context.applicationContext as Application)
You can see your "as" is incorrect. Try to create an empty ViewModel without context. It solves the problem with a preview
CodePudding user response:
I found the best way to get a Preview to work when you need to access something that's Android lifecycle-specific, e.g. Application, Activity, FragmentManager, ViewModel, etc, is to create an implementation of that interface that does nothing.
An example using FragmentManager:
@Composable
@OptIn(ExperimentalAnimationApi::class)
fun MyFragmentView(
fragmentManager: FragmentManager
) {
Button(modifier = Modifier.align(Alignment.End),
onClick = {
MyDialogFragment().show(fragmentManager, "MyDialogTag")
}
) {
Text(text = "Open Dialog")
}
}
Preview function:
object PreviewFragmentManager: FragmentManager()
@Preview
@Composable
fun MyFragmentViewPreview() {
MyFragmentView(
fragmentManager = PreviewFragmentManager
)
}
Now your Preview function will render.
You can do the same thing with ViewModel - just make your ViewModel extend an interface.
import androidx.compose.runtime.*
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.viewmodel.compose.viewModel
import kotlinx.coroutines.flow.StateFlow
interface MyViewModel {
val state: StateFlow<SomeState>
fun doSomething(input: String)
}
class MyViewModelImpl: MyViewModel, ViewModel() {
// implement interface's required values/functions
}
object PreviewViewModel: MyViewModel()
@Composable
fun MyView(viewModel: MyViewModel = viewModel<MyViewModelImpl>()) {
// UI building goes here
}
@Composable
@Preview
fun MyViewPreview() {
MyView(viewModel = PreviewViewModel)
}
In your case, I would suggest doing the steps for ViewModel outlined above, and not messing around with LocalContext whatsoever in your preview.