如何在jetpack compose上回收webview?

Posted

技术标签:

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

我有一个通过HorizontalPager 模拟ViewPager 行为的应用程序。每个寻呼机都有一个WebViewViewPager 会为远离当前页面的页面释放WebView。我应该在 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。

【讨论】:

以上是关于如何在jetpack compose上回收webview?的主要内容,如果未能解决你的问题,请参考以下文章

jetpack Compose绘制流程原理

jetpack Compose绘制流程原理

jetpack Compose绘制流程原理

如何使用 Jetpack Compose UI 在 Android 上正确跟踪屏幕视图?

如何在 Jetpack Compose 的 LazyColumn/LazyRow 中禁用和启用滚动?

在 Jetpack Compose 中单击时如何禁用涟漪效应