Home > other >  How to recycle a webview on jetpack compose?
How to recycle a webview on jetpack compose?

Time:12-01

I have an app that emulates ViewPager behavior via HorizontalPager. Each Pager has a WebView, and the ViewPager will release WebView for pages that are far from the current page. What should I do in Jetpack Compose? It seems the composable should not be destroyed

CodePudding user response:

You should add a function to the class that implements the WebView that calls onDestroy and replaces the current page with a blank page. Replacing the current web page with a blank page will terminate any javascript. For example, in my app I use a WebView to play YouTube videos:

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()
    }
}

You should call your termination function when the you navigate back to the previous screen. Whether you want to clear the webview when you swipe tabs is a decision you have to make. In my app, because I play videos in one tab, I need to terminate the video when the user swipes to another tab. But if your app is playing media content like videos, then you probably don't need to terminate the webview.

CodePudding user response:

This is expected behaviour. ViewPager is a lazy view and it's not gonna store non visible views.

In clear Compose all you need to cache is scrolling position and some other state variables, and Compose will do that.

But when you're using AndroidView, you had to manage it by yourself. I'm not sure if it's possible to retrieve WebView scrolling position, but even if you can - the page still will be re-loaded.

A possible solution is storing WebViews in a state like this:

val webViews = remember(LocalContext.current) { mutableStateMapOf<Int, WebView>() }
HorizontalPager(count = 5) { 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()
    )
}
  • Related