Is there any kind of mutex available that i can us...
# compose
m
Is there any kind of mutex available that i can use in drawWithCache ?
s
I believe people can better help you if you show a code sample of what you want to achieve and what currently is not working for you.
m
the problem is Dispatcher.IO, when saving is happening, a new recording can happen, which is illegal and crash
i need to somehow syncronize the two
s
I recently saw this post by @Rebecca Franks. Does it help maybe?
m
yes, i am using that approach. the problem is, that approach has a problem
when you create the bitmap from the Picture, endRecording must be called. Since you cannot control when the composable calls draw. You can try to save while the render process is in the middle
s
Hm, maybe Rebecca has an idea?
m
and that will crash
ok. ill try to ping her. thanks
s
Why do you use
<http://Dispatcher.IO|Dispatcher.IO>
?
m
its in the google sample. it can be heavy operation
s
I donโ€™t see a Dispatcher mentioned in the example here ๐Ÿ‘€
m
it is in the original link i provided. It is compose team sample ๐Ÿ˜›
coroutineScope.launch(<http://Dispatchers.IO|Dispatchers.IO>) {
val bitmap = createBitmapFromPicture(picture)
val uri = bitmap.saveToDisk(context)
shareBitmap(context, uri)
}
createBitmap happens in another dispatcher. Which can cause this problem
s
Hm, yeah, we need Rebecca who is the author of this code, I guess ๐Ÿ˜…
m
i can solve the problem keeping a Picture object per render. Which may be expensive also ๐Ÿ˜›
s
Have you tried the simple example from the website?
m
Again, the google sample as it is has this bug. I did no try rebeka approach, which i believe is similar. let me check
๐Ÿ‘๐Ÿผ 1
ya, its the same
๐Ÿค” 1
i solved with sth like this, no idea if it is expensive
z
@Rebecca Franks
m
I ended up doing something like this:
Copy code
private val pictureMutex = Mutex()
private val picture = Picture()

fun record(
        scope: ContentDrawScope,
        width: Int,
        height: Int
    ) {
        val locked = pictureMutex.tryLock()

        if (locked) {
            try {
                with(scope) {
                    val canvas = Canvas(picture.beginRecording(width, height))
                    draw(scope, scope.layoutDirection, canvas, scope.size) {
                        this@with.drawContent()
                    }
                    picture.endRecording()
                    drawIntoCanvas { drawCanvas ->
                        drawCanvas.nativeCanvas.drawPicture(picture)
                    }
                }
            } finally {
                pictureMutex.unlock()
            }
        } else {
            scope.drawContent()
        }
    }

    fun capture() {
        scope.launch {
            try {
                val bitmap = withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
                    pictureMutex.withLock {
                        createBitmapFromPicture(picture)
                    }
                }
            }
        }
    }
It will suspend while trying to create the bitmap until the recording is finished. If it is attempting to record while saving is happening, it will skip recording. I think it is a better solution, since it does not mess with the drawing phase. Feedback from @Rebecca Franks is needed!
s
@myanmarking FYI, when you use ````` (three backticks) you can properly format a block of code
๐Ÿ‘ 1
r
Thanks folks for the feedback, this doesn't sound great I agree. (cc @Nader Jawad too for context as he is also looking into improving the solution to use bitmaps with hardware acceleration across all versions of Android). Will revert back when we have an official solution here thank you color
๐Ÿ™๐Ÿผ 1
๐Ÿ™ 1
n
You can probably get away with removing the coroutine usage here to avoid concurrency concerns.
m
That why there is a mutex
The bitmap is heavy. Cannot use main thread
But ya. On the main thread no probs
n
It is reasonable to render content into an offscreen bitmap as part of a typical render pass. The Android graphics pipeline does this internally for various use cases when content is promoted to a layer. While we should persist these bitmaps/layers across frames, doing a 1 off render if not prohibitive if done sparingly.
๐Ÿ‘ 1
m
The usage of io dispatcher is in google examples, not mine. I just caught the problem here :)
n
@Rebecca Franks do you think we can update these samples here ๐Ÿ™‚
m
I think the mutex solution is reasonable. It wont suspend when drawing. It will just do draw pass without capturing anything
Il wait for official fix. Can confirm no problems so far
r
@Nader Jawad thanks - yup will do!
154 Views