https://kotlinlang.org logo
#compose
Title
# compose
f

fengdai

06/20/2022, 7:42 AM
Will
AndroidView
recreate view when
LocalContext.current
changed?
Wait… Can
LocalContext.current
change?
f

Filip Wiesner

06/20/2022, 8:03 AM
LocalContext
is
StaticCompositionLocal
which means that if it changes, it should recompose the whole composition tree.
Unlike compositionLocalOf, reads of a staticCompositionLocalOf are not tracked by the composer and changing the value provided in the CompositionLocalProvider call will cause the entirety of the content to be recomposed instead of just the places where in the composition the local value is used.
f

fengdai

06/20/2022, 8:22 AM
Thanks, Filip. So, the answer is no, since recomposition doesn’t trigger
AndroidView
to invoke its
factory
lambda again to recreate view. Am I right?
f

Filip Wiesner

06/20/2022, 8:24 AM
I think that the answer is yes. If I understand it correctly, the whole UI tree including the
AndroidView
is destroyed and created again.
f

fengdai

06/20/2022, 8:37 AM
Well, the recomposition doesn’t destroy and recreate the whole tree. It just re-execute the root composable function to update the tree.
The ‘root composable function’ is not accurate. It is the content of the
CompositionLocalProvider
where the value is provided.
f

Filip Wiesner

06/20/2022, 9:23 AM
I mean yeah but I bet the
AndroidView
depends on the context so if the context changes (and that is a big if), it should be recreated. Either way I would think that this is something the creators of Compose and more specifically
AndroidView
thought of and you should not have to think about things like this. Or do you have some specific use case that relies on this behavior?
f

fengdai

06/20/2022, 9:48 AM
If it does’t recreate the view, the previous context will be leaked. I believe that the Compose team can guarantee the correctness. I’m just curious about how the recreation is triggered (if it does recreate). But I can’t figure it out with the source code (maybe I missed something).
t

tad

06/20/2022, 4:57 PM
I'm struggling to think of a case where *re*composition can occur with a different Context. If it could, then the View system would be similarly broken.
Keep in mind that
setContent
and similar create a
ComposeView
.
f

fengdai

06/21/2022, 2:25 AM
I’ve verified. The answer is no. Here is my code:
Copy code
val localContext = LocalContext.current
var context by remember { mutableStateOf(localContext) }
CompositionLocalProvider(
    LocalContext provides context
) {
    Log.d("AndroidView", "compose: context - ${LocalContext.current}")
    AndroidView(factory = { context ->
        TextView(context).apply {
            Log.d("AndroidView", "create view: ${this.hashCode()}")
        }
    }) {
        Log.d("AndroidView", "update view: ${it.hashCode()}")
    }
}
LaunchedEffect(key1 = Unit) {
    delay(3000)
    context = ContextWrapper(context)
}
And log is:
Copy code
compose: context - sample.MainActivity@da29b84
create view: 162893151
update view: 162893151
compose: context - android.content.ContextWrapper@d588329
t

tad

06/21/2022, 2:44 AM
In Compose UI, the Context is what hosts ComposeView, which in turn runs the composition. If Context was able to change, then the View class hierarchy would be irreperably broken as it contains references to the containing Context all over the place. That said, there is no mechanism to enforce this that's exposed in the compose-ui API, so you'll have to either: trust that
LocalContext
is an immutable property of the composition, or; structure your code to make no assumptions about the runtime value of
LocalContext
. In practice, both stances are the same, because
staticCompositionLocalOf
will trigger a recomposition of everything, as it's set within
setContent
on Android; therefore you can't really avoid being recomposed.
In short, it will never change while your Activity is alive, hence all the APIs and years of contention about how to persist UI state on Android.
f

fengdai

06/21/2022, 3:00 AM
Thanks, Tad. Your answer clarifies
LocalContext
for me.
For anyone who is interested in my original question:
Will
AndroidView
recreate view when
LocalContext.current
changed?
Since: •
LocalContext.current
changes triggers recomposition. • Recomposition doesn’t trigger
AndroidView
to invoke its
factory
lambda again. So, the answer is no. https://kotlinlang.slack.com/archives/CJLTWPH7S/p1655778343809389?thread_ts=1655710925.339069&cid=CJLTWPH7S
66 Views