【问题标题】:How to recycle a webview on jetpack compose?如何在jetpack compose上回收webview?
【发布时间】:2022-01-07 07:03:01
【问题描述】:

我有一个通过HorizontalPager 模拟ViewPager 行为的应用程序。每个寻呼机都有一个WebViewViewPager 会为远离当前页面的页面释放WebView。我应该在 Jetpack Compose 中做什么?看来组合组件不应该被销毁

【问题讨论】:

    标签: android android-webview android-jetpack-compose


    【解决方案1】:

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

    在明确的 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()
        )
    }
    

    【讨论】:

    • 我认为如果WebView的Composable没有被调用,WebView应该被回收,所以也许我可以添加一个判断是否调用composable的条件
    • @Kennir “未调用 WebView”是什么意思?我只在它第一次出现时创建它
    • 嗨@philip-dukhov,我的意思是不要调用包含WebView的可组合函数如果当前索引足够远,例如: if (abs(pageIndex, currentIndex)
    • @Kennir HorizontalPager 工作很懒,它不会调用所有页面的内容。在初始加载时,它只会加载第一个和第二个项目。
    • 很抱歉我没有解释清楚,比如我想销毁第一页的webview释放内存,如果当前页面移动到3或更大,然后重新创建如果当前页面移回 2 或小则为 webview
    【解决方案2】:

    您应该向实现 WebView 的类添加一个函数,该函数调用 onDestroy 并将当前页面替换为空白页面。用空白页面替换当前网页将终止任何 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()
        }
    }
    

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

    【讨论】:

      猜你喜欢
      • 2022-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-05
      • 2023-01-18
      • 2020-03-03
      • 2023-01-03
      • 1970-01-01
      相关资源
      最近更新 更多