投射 LocalContext.current 时的 Jetpack Compose 预览渲染问题

Ant*_*tov 6 kotlin android-studio android-jetpack-compose android-jetpack-compose-preview

Android Studio Chipmunk 2021.2.1; \nCompose Version = \'1.1.1\'; \nGradle  Version 7.4.2; \nKotlin 1.6.10;\n
Run Code Online (Sandbox Code Playgroud)\n

直到某一时刻,一切都正常。然后,当我尝试在此项目和另一个项目中调用“LocalContext.current”并将“context.applicationContext 作为应用程序”时,出现此错误并且预览停止工作。它曾经与“LocalContext.current”一起使用的地方

\n

尝试过不同版本的 Compose、kotlin、gradle。

\n

渲染问题

\n
\n

java.lang.ClassCastException: 类\ncom.android.layoutlib.bridge.android.BridgeContext 无法转换为\n类 android.app.Application\n(com.android.layoutlib.bridge.android.BridgeContext 和\nandroid.app.应用程序位于 loader\ncom.intellij.ide.plugins.cl.PluginClassLoader @3a848149) \xc2\xa0\xc2\xa0at\ncom.client.personalfinance.screens.ComposableSingletons$AccountScreenKt$lambda-2$1.invoke( AccountScreen.kt:136)\n\xc2\xa0\xc2\xa0at\ncom.client.personalfinance.screens.ComposableSingletons$AccountScreenKt$lambda-2$1.invoke(AccountScreen.kt:133)\n\xc2\xa0\xc2 \xa0at\nandroidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)\n\xc2\xa0\xc2\xa0at\nandroidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm. kt:34)\n\xc2\xa0\xc2\xa0at\nandroidx.compose.material.MaterialTheme_androidKt.PlatformMaterialTheme(MaterialTheme.android.kt:23)\n\xc2\xa0\xc2\xa0at\nandroidx.compose.material。 MaterialThemeKt$MaterialTheme$1$1.invoke(MaterialTheme.kt:82)\n\xc2\xa0\xc2\xa0at\nandroidx.compose.material.MaterialThemeKt$MaterialTheme$1$1.invoke(MaterialTheme.kt:81)\n\xc2\ xa0\xc2\xa0at\nandroidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)\n\xc2\xa0\xc2\xa0at\nandroidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda .jvm.kt:34)\n\xc2\xa0\xc2\xa0at\nandroidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)\n\xc2\xa0\xc2\xa0at androidx.compose.material。 TextKt.ProvideTextStyle(Text.kt:265

\n
\n
@Preview(showBackground = true) \n@Composable fun PrevAccountScreen() {\n    val context  = LocalContext.current\n    val mViewModel: MainViewModel =\n             viewModel(factory = MainVeiwModelFactory(context.applicationContext as Application))\n    AccountScreen(navController = rememberNavController(), viewModel = mViewModel)\n }\n
Run Code Online (Sandbox Code Playgroud)\n

Cha*_*ejo 3

我发现,当您需要访问特定于 Android 生命周期的内容(例如应用程序、活动、FragmentManager、ViewModel 等)时,让预览版正常工作的最佳方法是创建该接口的一个不执行任何操作的实现。

使用 FragmentManager 的示例:

@Composable
@OptIn(ExperimentalAnimationApi::class)
fun MyFragmentView(
    fragmentManager: FragmentManager
) {
    Button(modifier = Modifier.align(Alignment.End),
           onClick = {         
              MyDialogFragment().show(fragmentManager, "MyDialogTag")
           }
    ) {

        Text(text = "Open Dialog")
    }

}
Run Code Online (Sandbox Code Playgroud)

预览功能:

object PreviewFragmentManager: FragmentManager()

@Preview
@Composable
fun MyFragmentViewPreview() {
    MyFragmentView(
        fragmentManager = PreviewFragmentManager
    )
}
Run Code Online (Sandbox Code Playgroud)

现在您的预览功能将呈现。

您可以使用 ViewModel 做同样的事情 - 只需让您的 ViewModel 扩展一个接口即可。

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)
}
Run Code Online (Sandbox Code Playgroud)

对于您的情况,我建议执行上述 ViewModel 的步骤,而不是在预览中搞乱 LocalContext。