https://kotlinlang.org logo
Title
s

Sergio C.

03/22/2022, 5:29 PM
Hi all, I was trying to use
callbackFlow { }
but the code inside the block never gets called, am I doing something wrong?
j

Joffrey

03/22/2022, 5:31 PM
If you share how you declare and use your
callbackFlow
, we should be able to answer this 😉
e

ephemient

03/22/2022, 5:34 PM
flow()
and
channelFlow()
are cold flows, they only run when collected
s

Sergio C.

03/22/2022, 5:45 PM
already rewritten everything but I had a ViewModel with
fun getSensors(): LiveData<ReadResult> {
    return sensorsRepository.getSensorsFLow().asLiveData()
}
in the repository
private var data: Flow<ReadResult> = MutableSharedFlow()
init {
    CoroutineScope(<http://Dispatchers.IO|Dispatchers.IO>).launch {
        val dataStore: DataStore<AppPreferences> = app.appPreferencesStore
        dataStore.data.catch {
            updateObservers(AppPreferences.getDefaultInstance())
        }.collectLatest {
            updateObservers(it)
        }
    }
}
private fun updateObservers(appPreferences: AppPreferences) {
    stopSensors()
    when (appPreferences.selectedDevice) {
        AppPreferences.Device.SUNI -> initSuniReader()
        AppPreferences.Device.TZ702 -> initTZReader()
        AppPreferences.Device.NEXPEK7 -> initNexpekReader()
        else -> flowOf(ReadResul())
    }
}
private fun initNexpek(): Flow<ReadResult> {
    return callbackFlow<ReadResult> {
        init sensor and wait for callback
        trySend(the result)
     }
 }
Sensor was not initiated
Now I have
private var data: MutableSharedFlow<ReadResult> = MutableSharedFlow()
and everyone sends data to it with tryEmit
j

Joffrey

03/22/2022, 5:48 PM
You probably forgot the
awaitClose()
call at the end of the
callbackFlow
block
But note that
callbackFlow
is meant for multi-shot callbacks. If you want to encapsulate a single-shot callback you should make a
suspend
function returning a single value instead of a flow, and you can build that function using
suspendCancellableCoroutine
. I'm not sure which one is your case though
s

Sergio C.

03/22/2022, 5:49 PM
just add
awaitClose()
inside the lock?
I can have multiple return events from the sensor
I will try this later
thanks for the tips
j

Joffrey

03/22/2022, 5:51 PM
In general if you want to encapsulate a multi-shot callback into a Flow, you also want to unregister the callback / stop the emitter when the flow is cancelled or completed. This is what you would do inside the
awaitClose { }
block. Check the documentation of
callbackFlow
s

Sergio C.

03/22/2022, 6:10 PM
ok
I need more practice with Flows.
also using tryEmit from different places to the same MutableSharedFlow seems like a valid approach, what do you think?
e

ephemient

03/22/2022, 6:20 PM
updating a MutableStateFlow from different places would be the closest equivalent to LiveData (without being tied to the UI thread)
having mutation from multiple places does not sound like a good design, though
1
s

Sergio C.

03/22/2022, 11:39 PM
ok. any other approach I could take?
g

gildor

03/23/2022, 1:50 AM
Cold flow is usually better approach. It really depends on your case