如何在 Jetpack Compose 上回收 WebView?

How to recycle a webview on jetpack compose?

我有一个通过 HorizontalPager 模拟 ViewPager 行为的应用程序。每个Pager都有一个WebViewViewPager会为远离当前页面的页面释放WebView。我应该在 Jetpack Compose 中做什么?似乎不应该销毁可组合项

您应该向 class 添加一个函数来实现调用 onDestroy 的 WebView 并将当前页面替换为空白页面。用空白页面替换当前网页将终止任何 javascript。例如,在我的应用程序中,我使用 WebView 来播放 YouTube 视频:

class VideoPlayerView() : WebView(ctx) {
    fun terminateWebView() {
        // Reload the webview with a blank page. This is needed to kill any video playing.
        loadData("<html><body></body></html>", "text/html", "base64")
        this.destroy()
    }
}

当您导航回到上一屏幕时,您应该调用终止函数。滑动标签时是否要清除 webview 是您必须做出的决定。在我的应用程序中,因为我在一个选项卡中播放视频,所以我需要在用户滑动到另一个选项卡时终止视频。但是,如果您的应用不播放视频等媒体内容,那么您可能不需要终止 webview。

这是预期的行为。 ViewPager 是惰性视图,不会存储不可见视图。

在 Clear Compose 中,您需要缓存的只是滚动位置和一些其他状态变量,Compose 会做到这一点。

但是当您使用 AndroidView 时,您必须自己管理它。我不确定是否可以检索 WebView 滚动位置,但即使可以 - 页面仍会重新加载。

一种可能的解决方案是将 WebViews 存储在这样的状态中:

val webViews = remember(LocalContext.current) { mutableStateMapOf<Int, WebView>() }
val state = rememberPagerState()
LaunchedEffect(state.currentPage) {
    webViews.keys.forEach { key ->
        val maxCacheDistance = 3
        if (abs(key - state.currentPage) >= maxCacheDistance) {
            webViews.remove(key)
            println("webView $key deinited")
        }
    }
}
HorizontalPager(
    count = 10,
    state = state,
) { page ->
    val url = "https://duckduckgo.com/?q=$page"
    AndroidView(
        factory = { context -> 
            webViews[page] ?: run {
                WebView(context).also { webView ->
                    webView.settings.javaScriptEnabled = true
                    webViews[page] = webView
                }
            }
        },
        update = { webView ->
            if (webView.url != url) {
                webView.loadUrl(url)
            }
        },
        modifier = Modifier.fillMaxSize()
    )
}