Hi, I'm encountering a bug which I suspect might b...
# compose
a
Hi, I'm encountering a bug which I suspect might be State not causing recomposition if updated the same frame it is created (eg https://kotlinlang.slack.com/archives/CJLTWPH7S/p1585902276072100). My use case is that I have a feed view and a detail view which both load images using Picasso. When entering the detail view, the image is already in the cache and loads instantly which seems to make the detail image stuck in the loading state. Placing a
delay(1)
seems to make it work as intended, but feels extremely hacky. What would be the idiomatic solution for this?
Copy code
val imageState = stateFor<ImageState, String>(imageUrl) { ImageState.Loading }

launchInComposition(imageUrl) {
    delay(1)
    imageState.value = loadImage(imageUrl, targetWidthPx, targetHeightPx)
}
l
I think this is happening because launchInComposition fires in onEnter. We should probably ensure that onEnter happens in a different frame from composition. Does that seem right to you @Chuck Jazdzewski [G] @Adam Powell? This seems like perfectly valid usage
(Adrian’s usage. The quoted usage from Minghao is arguably different because that is happening synchronously in composition)
That said, this code is still not ideal in the sense that it will compose with a loading state for a frame even though the image is already loaded and cached and can be accessed synchronously. Adrian: If possible in your code, if you have a non-side-effectful
getImage
method that will address your cache synchronously, that would be the best thing to use in the state lambda
a
a lot of this is changing with the frames => snapshots migration, I would need to have a closer look. We have a bunch of kind of weird loopback to composition patterns we should try to avoid though, as you note.
I gave some thought to trying to be tricky about undispatched launches during composition for cases like this, where we could cancel the coroutine if the composition doesn't land but allow side-effect free operations until first suspend that would behave more or less like the body of a
remember
- it seems like a total run-with-scissors API to have around though.
not the least of which because it would imply unconfined threading until first suspend which a lot of APIs people would interact with might not be prepared for
to the immediate point though: if changing a
MutableState
in an
onEnter
doesn't schedule recomposition of readers it's a bug and we should fix it.
If you need a janky workaround for now, probably prefer
yield()
over
delay(1)
👍 1
c
This was indeed changed slightly with the transition to snapshots. @Adrian Blanco’s cas should work correctly and @molikto's case is an example of an unsupported backwards write.
👍 1
l
Will it though if onEnter is happening in same snapshot as composition? That is what I think we need to change
c
onEnter
happen outside of a snapshot.
Turns out this is not exactly true. If the
onEnter
is inside a
WithConstraints
or any other sub-composition then the
onEnter
is run inside the outer composition's snapshot. I created issue 160597664 to track this.