androidandroid-jetpack-compose

How can I prevent my WebView from causing lag in the parent Composable?


I have the following code:

@Composable
fun WebTest(modifier: Modifier) {
    val url = "https://www.google.com"
    val ctx = LocalContext.current

    Column(modifier = modifier) {
        Text("title", fontSize = 22.sp, modifier = Modifier.fillMaxWidth().height(44.dp))
        AndroidView(
            modifier = Modifier.fillMaxWidth().fillMaxHeight(), 
            factory = { WebView(ctx) }, 
            update = {
                it.loadUrl(url)
            }
        )
    }
}

In this case, the "title" Text always show after the WebView was loaded into the AndroidView, but it is supposed to be shown immediately.

If I comment out the code it.loadUrl(url), the "title" Text will never show.
If I change WebView to FrameLayout, it work fine.

Why the "title" Text cannot be show immediately?


Solution

  • The AndroidView invocation is the bottleneck here. Even if you construct the View outside of the composition, there is a significant lag when the View is applied to the AndroidView. This results in a very slow recomposition, where the whole Composable will go blank until all nested Composables were laid out.

    However, the LazyColumn is an exception here - as it lazily loads and lays out its children without affecting the recomposition of the parent Composable. This allows the following workaround:

    @OptIn(ExperimentalMaterial3Api::class)
    @Composable
    fun WebTest(modifier: Modifier = Modifier) {
        val url = "https://www.google.com"
        val ctx = LocalContext.current
    
        Column(modifier = modifier) {
            TopAppBar(
                title = { Text(text = "WebView Demonstration") },
            )
            LazyColumn(
                modifier = Modifier.weight(1f).fillMaxHeight(),
                userScrollEnabled = false  // to let the AndroidView consume scrolling
    
            ) {
                item {
                    AndroidView(
                        modifier = Modifier.fillParentMaxSize(),
                        factory = { WebView(ctx) },
                        update = {
                            it.webViewClient = WebViewClient();
                            it.loadUrl(url)
                        }
                    )
    
                }
            }
        }
    }
    

    Comparison without / with LazyColumn:

    no LazyColumn with LazyColumn