当有 NavigationBar 时,Compose 导航会在屏幕内重新实例化 WebView

问题描述 投票:0回答:1

我目前正在按照 docs 测试撰写导航。考虑有两个屏幕,分别称为 HomeWeb。导航使用如下:

@Composable
fun ButtonNavigationApp() {
    val navController = rememberNavController()

    Scaffold(
       bottomBar = { BottomNavigationBar(navController) }
    ) { innerPadding ->
       NavHost(
           navController = navController,
           startDestination = "Home"
       ) {
           addHomeScreen()
           addWebScreen()
       }
    }
}

主屏幕:

fun NavGraphBuilder.addHomeScreen() {
    composable("Home") {
        Text("Home is here")
    }
}

网页屏幕:

fun NavGraphBuilder.addWebScreen() {
    composable("Web") {
        AndroidView(
            onReset = {}, // Add to reuse the view as documentation says.
            factory = { context ->
                WebView(context).apply {
                    // Initializing web-view here
                }
            },
            update = { it.loadUrl("google.com") }
        )
    }

}

导航栏:

@Composable
fun BottomNavigationBar(navController: NavHostController) {
    ...
    
    NavigationBar {

        NavigationBarItem(
         ...
           onclick = { 
               navController.navigate("Home") {
                   popUpTo(navController.graph.startDestinationId) { saveState = true }
                   launchSingleTop = true
                   restoreState = true
               }
           }
         ...
        )

        NavigationBarItem(
         ...
           onclick = { 
               navController.navigate("Web") {
                   popUpTo(navController.graph.startDestinationId) { saveState = true }
                   launchSingleTop = true
                   restoreState = true
               }
           }
         ...
        )
    }
}

问题:Home 导航到 Web 屏幕时,URL 按预期加载。单击 Home,然后单击 Web 时,将再次加载 url(尽管视图模型仍然存在)。

我检查并发现撰写屏幕正在重新创建,因此网络视图再次重新创建。如何强制导航不创建 Web 视图的另一个实例?

android android-jetpack-compose android-webview jetpack-compose-navigation
1个回答
0
投票

您遇到的问题源于使用 popUpTo 导航选项,这会导致 Web 屏幕的可组合项在您每次导航到它时被破坏并重新创建。这会导致 WebView 重新初始化并重新加载 URL。

从导航操作中删除 popUpTo

在 BottomNavigationBar 中,从 navController.navigate 调用中删除 popUpTo 选项:

NavigationBarItem(
    ...
    onClick = {
        navController.navigate("Web") {
            launchSingleTop = true
            restoreState = true
        }
    }
    ...
)

对“主页”导航执行相同操作:

NavigationBarItem(
    ...
    onClick = {
        navController.navigate("Home") {
            launchSingleTop = true
            restoreState = true
        }
    }
    ...
)

使用remember保留WebView实例

在 addWebScreen 函数中,使用记住在重组中保留 WebView 实例:

fun NavGraphBuilder.addWebScreen() {
    composable("Web") {
        val context = LocalContext.current
        val webView = remember { WebView(context) }

        DisposableEffect(Unit) {
            onDispose {
                webView.destroy()
            }
        }

        AndroidView(
            factory = { webView },
            update = {
                if (webView.url == null) {
                    webView.loadUrl("https://www.google.com")
                }
            }
        )
    }
}

避免弹出返回堆栈:通过不使用 popUpTo,Web 可组合项保留在导航堆栈中,保留其状态。 使用记住:这可以使 WebView 在重组过程中保持活动状态,从而防止它重新加载 URL。 正确的清理:DisposableEffect 确保当可组合项离开组合时 WebView 被销毁,从而避免内存泄漏。

© www.soinside.com 2019 - 2024. All rights reserved.