<@UHAJKUSTU> I have onResume callback triggered tw...
# decompose
e
@Arkadii Ivanov I have onResume callback triggered twice in the same time. What can be the reason?
Copy code
init {
        lifecycle.doOnResume {
            log(" lifecycle.doOnResume")
            store.accept(Intent.RefreshLocationStatus)
            store.accept(Intent.RefreshSelfieStatus)
        }
    }
a
I'm not sure. It would be nice to capture the stack trace of both invocations.
e
a
Interesting. Are you sure both calls are performed in the same instance of the component? I feel like you have duplicated instances for some reason. Worth also capturing the stack trace in the
init
section.
e
yes, I’ve checked that
a
Would it be possible to provide a reproducer?
e
Sure, I will try, but only when I return to this bug. Thank you!
🙏 1
a
Another user reported this issue with a reproducer and it turned out to be a bug in Decompose. It happens if the root component is lazily initialised (e.g.
private var root by lazy { ... }
) and the property is first accessed inside
setContent { ... }
block. I will fix it soon. Meantime, a workaround is to access the
root
property right before calling
setContent
, so that the root component is created earlier.
e
Wow, thank you so much for this update! How does this bug caused inside Decompose, how does it work?
a
Sure! It turned out to be an edge case with Jetpack Lifecycle. If the Jetpack Lifecycle is in a state higher than INITIALIZED (e.g. RESUMED), and you add an observer via
addObserver
method, it may skip calling the callbacks synchronously (before addObserver call returns) if another dispatch is currently being performed. In other words, if you call
addObserver
from another Lifecycle callback, the new callbacks are not called synchronously, but eventually once the current dispatch is finished. This is the case when you wrap the root component creation in
Lazy
and access it for the first time from
setContent {}
block. The
setContent {}
block is internally called from a Lifecycle callback. At this point the Jetpack Lifecycle is in RESUMED state. The root component, the stack and the child component are being created. And there is a bug in Decompose MergedLifecycle, as it currently relies on parent Lifecycles to call callbacks synchronously on subscription, which is not always the case. As a result, it subscribes to both parent
lifecycle1
and
lifecycle2
, where
lifecycle2
is a wrapped Jetpack Lifecycle in RESUMED state, but its callbacks are not called synchronously. First
lifecycle1
dispatches its callbacks normally (triggered by Child Stack) - the resulting child Lifecycle goes INITIALIZED -> CREATED -> STARTED -> RESUMED, because it sees Jetpack Lifecycle is in RESUMED state. Then the Jetpack Lifecycle finally dispatches its callbacks, it calls onCreate first - the resulting Lifecycle goes RESUMED -> STARTED -> CREATED. Then it calls onStart and onResume - and the result Lifecycle goes CREATED -> STARTED -> RESUMED. This might sound confusing, but here is a fix with tests: https://github.com/arkivanov/Decompose/pull/698. Hope it helps.
e
very interesting, thank you!
👍 1