Is it possible to detect recompositions happening ...
# compose
z
Is it possible to detect recompositions happening to child composables from the parent?
z
No. What are you trying to do?
z
https://kotlinlang.slack.com/archives/CJLTWPH7S/p1701842616778049?thread_ts=1701842616.778049&cid=CJLTWPH7S 🥲🥲 So basically just trying to find a way to trigger my capture logic for the nested composable.
z
Don’t understand why you want to observe free composition to trigger this. Drawing it often is intentionally invalidated without invalidating composition at all.
z
Maybe there's an error in how I'm capturing the contents? I'm just trying to figure out a way to ensure I always get the end stage of my composable in the resulting bitmap, otherwise animating elements aren't captured - and they make up like 90% of what I'm trying to capture 😅 Most of the code is copy paste of the "how to capture your composable into a bitmap guide" that was floating around a while back when
Picture
was introduced.
If you have time to get into it. How would you capture the contents of a composable into a bitmap continiously whenever it changes? 🙂
z
I don’t think that’s possible to do efficiently currently. The draw scope that’s doing the capture would need to be invalidated every time any draw scope below it is invalidated, which would probably break a bunch of optimizations since that is wasted work usually. That said, if you know the start and end points that you want to capture, you could use withFrameNanos to force your capture scope to invalidate on every frame.
z
Efficiency set aside, is it possible to invalidate it like that? Id like to at least try if I can, the screen itself is static after the animations, you cant interact with the underlying/nested elements. Will play around with withFrameNanos in the meantime!
Im fairly certain that this has the same issue as me. AsyncImage, etc, is apparently not being captured correctly. Guessing its because of the loading and/or animations. Also using
Picture
.
Findings thus far... I can use
withFrameNanos
and
drawModifierNode.invalidateSubtree()
but that kind of creates an endless loop. I put a
delay(500)
in there, but obviously that doesnt feel like a good solution. Ideally Id just like to recreate it when the content changes, but havent found a way to do that yet. Please let me know if you have any other ideas @Zach Klippenstein (he/him) [MOD] 😃 As mentioned above, the screen is static after animations finish, so I think I can get away with quite a bit of hax, I just dont like the idea of it continiously invalidating itself every .5s forever, Im also not sure if that will cause an OOM eventually.
z
You only need to invalidate draw, not layout and everything else. Don’t call
invalidateSubtree
, call
invalidateDraw
. Here’s a demo: https://r.android.com/2873994
One thing that demo doesn’t do is manually invalidate the preview on every frame, but leaving that as an exercise since that part isn’t what you were asking about anyway
z
Wow, I am humbled! Thank you, diving into it right away 😃
That was awesome. Thank you Zach! Biggest takeaways for me: Rendering each Picture into the same Bitmap is very smart, I was creating one Bitmap for each Picture capture (so, 2-3 in total). Insane speed boost just from that, which might by itself be enough to make the content feel like its "still there" when navigating back, which was the core issue I had. Seeing withFrameNanos in action was cool too, ultimately I couldnt apply it to my case since Ill end up creating a new blurred bitmap on every frame forever, or until the OOM reaper comes. Lastly it was great just seeing how you used the modifier system for a bit more complex case than normal!
👍🏻 1
s
@Zach Klippenstein (he/him) [MOD] what do you think of this approach?: https://github.com/PatilShreyas/Capturable/blob/master/capturable/src/main/java/dev/shreyaspatil/capturable/Capturable.kt#L231 In this, with the help of
DelegateNode
, I delegate work to
CacheDrawModifierNode
when capture request is received then I draw content in canvas and as soon as content is drawn, the node is un-delegated. It means that issue (as seen in the demo) doesn’t occur at all. Is it a good approach?