fengdai
05/26/2022, 5:32 AMMyState
, which implements the RememberObserver
interface. I do cleanup stuff in onForgotten
and onAbandoned
.
I use remember
to remember the MyState
instance:
val state = remember { MyState() }
And I configure my activity to handle configuration changes automatically in this way in my AndroidManifest.xml:
android:configChanges="colorMode|density|fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode"
So the instance will be kept across configuration changes.
When I changed the activity’s orientation, state
was kept, just as I expected. What I didn’t expect is that the MyState
’s onForgotten
method was called. This behavior left my remembered MyState
instance in a wrong state.
Is it a bug?fengdai
05/26/2022, 5:35 AMstate
is used in conditional flows, like this:
val state = remember { MyState() }
if (!isLandscape) {
Normal(state)
} else {
Landscape(state)
}
fengdai
05/26/2022, 6:08 AMfengdai
05/26/2022, 6:17 AMMyState
:
https://github.com/fengdai/compose-media/blob/de29aa1d84d991beb99b55a4322ed004d08b[…]a/src/main/java/com/github/fengdai/compose/media/PlayerState.kt
And this sample can reproduce the issue:
https://github.com/fengdai/compose-media/blob/de29aa1d84d991beb99b55a4322ed004d08b[…]/src/main/java/com/github/fengdai/compose/media/sample/Basic.ktZach Klippenstein (he/him) [MOD]
05/26/2022, 11:41 AMCompose may implicitly remember an object if doing so is required to restart the composition later, such as for composable function parameters.
If a single instance is remembered in more than one location in the same composition, its onRemembered and onForgotten will be called for each location in the composition.
A RememberObserver reference that is propagated to multiple parts of a composition might remain present in the composition for longer than expected if it is remembered (explicitly or implicitly) elsewhere, and a RememberObserver that appears more once can have its callback methods called multiple times in no meaningful order and on multiple threads.
fengdai
05/26/2022, 12:23 PMfengdai
05/26/2022, 2:05 PMkey
function usage in the conditional branch is also relevant:
val state = remember { MyState() }
if (!isLandscape) {
key(state) {
// do something
}
Normal(state)
} else {
Landscape(state)
}
fengdai
05/26/2022, 2:05 PMfengdai
05/26/2022, 2:20 PMnatario1
05/26/2022, 2:34 PMZach Klippenstein (he/him) [MOD]
05/26/2022, 4:00 PMNormal
and Landscape
are composable functions? So you're “passing a RememberObserver
as a composable function parameter”. The runtime will implicitly remember those values to enable skipping, and when you remove one of them from the composition it will get an onForgotten
call.fengdai
05/26/2022, 9:22 PMonRemembered
call when it is implicitly remembered again?Zach Klippenstein (he/him) [MOD]
05/26/2022, 9:25 PMZach Klippenstein (he/him) [MOD]
05/26/2022, 9:26 PMLeland Richardson [G]
05/26/2022, 10:10 PMkey(state)
is causing onForgotten to get called but not onRemembered, which would be a bugLeland Richardson [G]
05/26/2022, 10:12 PMLeland Richardson [G]
05/26/2022, 10:13 PMLeland Richardson [G]
05/26/2022, 10:14 PMclass MyState : RememberObserver {
val isAvailable get() = remembered - forgotten > 0
private var remembered = 0
private var forgotten = 0
override fun onRemembered() {
remembered++
}
override fun onAbandoned() {
remembered--
}
override fun onForgotten() {
remembered--
}
}
fengdai
05/26/2022, 10:21 PMisAvailable
still will be false after two screen rotations.Leland Richardson [G]
05/27/2022, 3:07 AMfengdai
05/27/2022, 3:17 AMremembered: 1
forgotten: 0
And second rotation:
remembered: 0
forgotten: 0
Leland Richardson [G]
05/27/2022, 3:19 AMnatario1
05/27/2022, 3:21 AMforgotten
will always be 0. So it’s probably 2/1 resulting in 1Leland Richardson [G]
05/27/2022, 3:23 AMLeland Richardson [G]
05/27/2022, 3:23 AMfengdai
05/27/2022, 3:24 AMLeland Richardson [G]
05/27/2022, 3:25 AMLeland Richardson [G]
05/27/2022, 3:26 AMforgotten--
instead of remembered--
?fengdai
05/27/2022, 3:28 AMLeland Richardson [G]
05/27/2022, 3:29 AM