julioromano
02/25/2021, 1:14 PMAndroidView
with a WebView
inside and every time it becomes visible again it will recompose and therefore reload the website. Any ideas how to get around this?Colton Idle
02/25/2021, 3:23 PMZach Klippenstein (he/him) [MOD]
02/25/2021, 3:47 PMAndroidView
or WebView
here, or you’re triggering a reload in the composable directly instead of using an effect.julioromano
02/25/2021, 6:42 PMfactory
param is stateless whilst the stuff that changes goes in the update
lambda). Am I doing it wrong?
@Composable
fun MyWebView(url: String) {
AndroidView(
factory = {
WebView(it)
}
) {
it.loadUrl(url)
}
}
url
changes it will recompose but in my case it’s not changing.Zach Klippenstein (he/him) [MOD]
02/25/2021, 7:23 PMloadUrl
that lambda you’re calling it.loadUrl
from, i believe, is the update function. It should effectively be idempotent, and should typically only set state on your view.
loadUrl
is, from what you described, a side effect. It’s not just setting some state, it’s actually triggering an action. That’s the problem.
Instead, you should save the WebView
instance somewhere (e.g. a MutableState
in your composable), then use a DisposableEffect
or something to trigger the load.
E.g.:
@Composable fun MyWebView(url: String) {
var webView by remember { mutableStateOf<WebView?>(null) }
AndroidView({ context ->
WebView(context).also { webView = it }
})
DisposableEffect(webView, url) {
webView.loadUrl(url)
onDispose {
webView.cancelLoading()
}
}
}
julioromano
02/25/2021, 7:30 PMYes,that lambda you’re callingloadUrl
from, i believe, is the update function. It should effectively be idempotent, and should typically only set state on your view.it.loadUrl
loadUrl()
is a method of the WebView
class. I thought that calling it was actually “setting state on my view” (isn’t the currently shown url an internal state of the WebView?).
It’s not just setting some state, it’s actually triggering an action. That’s the problem.I think I’m not getting it: What is the triggered action? I really thought it was setting state on the webview.
Instead, you should save the WebView instance somewhere (e.g. a MutableState in your composable), then use a DisposableEffect or something to trigger the load.Sounds like a plan! I’ll try that, thanks a lot!
Zach Klippenstein (he/him) [MOD]
02/25/2021, 8:11 PMloadUrl
is pretty much useless: “Loads the given URL.” No duh.
But from the behavior you’re describing, it sounds like calling loadUrl
triggers the web view to load the page from scratch every time, even if it’s the same URL as the view is currently showing. That’s why I’m thinking it’s actually a side effect and not an idempotent state setter.loadUrl
actually were idempotent and nooped if the same value was sent twice, it should probably be called setUrl
, and then your code would be correct.julioromano
02/25/2021, 8:17 PMThat’s why I’m thinking it’s actually a side effect and not an idempotent state setter.Very clear, thanks for the explanation. Now I got the nuance.
MyWebView
is conditionally called inside another composable (it’s a tabbed screen: depending on the active tab the code will either call MyWebView()
or another composable instead.
My compose mental model is not accurate enough but I have the feeling that when the other tab is active, the MyWebView
composable is removed from the composition, therefore when switching tabs again it is ~re~composed from scratch and therefore it reloads the website.loadUrl
is called again, but also the factory
lambda is.var webView by remember { mutableStateOf<WebView?>(null) }
up to the outer composable.
This way the webview keeps its state (even the web page scroll position) unfortunately when switching tabs there’s still a visual artifact: the webview “flashes” once (it appears, then briefly disappears and then reappears).Zach Klippenstein (he/him) [MOD]
02/26/2021, 12:47 AMI have the feeling that when the other tab is active, theAh, yea that sounds rightcomposable is removed from the compositionMyWebView