https://kotlinlang.org logo
Title
u

ursus

06/13/2021, 9:47 AM
Is using runBlocking correct way to interface with blocking world when using MutableStateFlow?
class PermissionManager() {
    private val manualTrigger = MutableSharedFlow<Unit>()
    
    ...

    fun notifyPermissionChanged() {
        runBlocking { <---------------------
            manualTrigger.emit(Unit)
        }
    }
}

class Activity {
	override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        permissionManager.notifyPermissionChanged()
    }
}
tryEmit never does anything
🇳🇴 1
b

Big Chungus

06/13/2021, 9:55 AM
You should dispatch it on Dispatchers.IO instead. runBlocking is meant to be used as an entrypoint only
u

ursus

06/13/2021, 10:08 AM
not sure what you mean. that down stream processing will happen on Activity thread? yea im aware
b

Big Chungus

06/13/2021, 10:10 AM
No I'm saying that you should use async(Dispachers.IO) {} instead of runBlocking. Otherwise you risk blocking UI thread
u

ursus

06/13/2021, 10:12 AM
do you mean GlobalScope.async/launch?
b

Big Chungus

06/13/2021, 10:13 AM
You should avoid global scope too. There was an article about that by @elizarov a while ago, but I can't find it for you now.
Google "globalScope us bad" or smth. It was on medium
u

ursus

06/13/2021, 10:14 AM
I'm aware, but creating a scope just to pipe the event in feels contraproductive, I'd rather just block the thread for the 0.1ms it takes.. since im the type which has private scope instances, not injected
b

Big Chungus

06/13/2021, 10:15 AM
If you're ok blocking main thread then go ahead with runBlocking. Nothing wrong with that
u

ursus

06/13/2021, 10:15 AM
I see, thanks! btw any obvious reason tryEmit doesnt work?
b

Big Chungus

06/13/2021, 10:16 AM
Or you can just make that function suspend
u

ursus

06/13/2021, 10:16 AM
which one, the notify?
b

Big Chungus

06/13/2021, 10:16 AM
Yes
u

ursus

06/13/2021, 10:17 AM
I'd rather not, im just trying to bridge blocking to reactive world, hence the mutableflow; and coming from rxjava it catches me offguard that the emit is a suspend function
b

Big Chungus

06/13/2021, 10:17 AM
I personally try to keep my entire app in suspend mode when working with coroutines.
u

ursus

06/13/2021, 10:18 AM
yes, all after the proxy is coroutine/flow world
b

Big Chungus

06/13/2021, 10:18 AM
I think there are rxjava extensions for coroutines to help converting between the two if that helps you at all
u

ursus

06/13/2021, 10:19 AM
not really necessary, its just that flow surfaces the need for backpressure handling of piping in emits into the relay/mutableflow, rx implicitly would block the activity thread if backpressure were to happen, here its obvious via runblocking
j

Javier

06/13/2021, 12:16 PM
async(<http://Dispatchers.IO|Dispatchers.IO>) { ... }
you mean
suspend
+
withContext(<http://Dispatchers.IO|Dispatchers.IO>) { ... }
? I can't find an async function
b

Big Chungus

06/13/2021, 12:47 PM
async is an extension to coroutineScope
j

Javier

06/13/2021, 2:27 PM
but where he is using runBlocking it isn't a suspend fun so he has no scope there
b

Big Chungus

06/13/2021, 2:42 PM
Thus me mentioning workarounds around GlobalScope
u

ursus

06/13/2021, 3:33 PM
@Adam Powell says no? rather to GlobalScope.launch it?
a

Adam Powell

06/13/2021, 3:57 PM
use a buffer or reconsider whether multicast events are the right tool here
f

Francesc

06/13/2021, 5:51 PM
tryEmit will fail if there are no subscribers to the flow. You can use the
extraBufferCapacity
parameter to ensure the flow will accept your value
👍 1
☝️ 1
u

ursus

06/13/2021, 6:22 PM
I don't think I follow. I'm trying to turn android callback into reactive events, but since it's Activity callback for the permissions, I can only imperatively proxy the events via MutableSharedFlow, no? What else is there to be done? I cannot wrap it cold-ly as I would with BroadcastReceiver and CallbackFlow for example
k

KamilH

06/14/2021, 5:26 AM
As Francesc said, what you are looking for is:
val manualTrigger = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
it will let you use
MutableSharedFlow.tryEmit
. You can read more about why you need this here: https://itnext.io/mutablesharedflow-is-kind-of-complicated-61af68011eae
u

ursus

06/14/2021, 8:07 PM
oh that's some footgun