Skip to content

Instantly share code, notes, and snippets.

@levibostian
Last active August 29, 2025 19:51
Show Gist options
  • Save levibostian/7002a0146e2b217bbd1f710e85a09cab to your computer and use it in GitHub Desktop.
Save levibostian/7002a0146e2b217bbd1f710e85a09cab to your computer and use it in GitHub Desktop.
android databinding ObservableBoolean to Kotlin Coroutine Flow
import androidx.databinding.Observable
import androidx.databinding.ObservableBoolean
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.distinctUntilChanged
/**
* Converts an ObservableBoolean to a Kotlin Flow.
*
* Benefits of using this:
* - Allows us to slowly migrate away from ObservableBoolean by being able to implement the code just like it was a Flow.
* We can then later replace the ObservableBoolean with a StateFlow or similar.
* https://steelseries.atlassian.net/browse/EMA-726
* - ObservableBoolean callbacks get called on whatever thread the change happens on. This can lead to unexpected app crashes
* when you, for example, try to update the UI from a background thread. This is easier to avoid with Flows since you can
* call `.collect{}` on a Flow and specify the dispatcher to use (which determines the thread to run the code on).
*
* The Flow will emit the current value immediately and then emit subsequent changes.
*
* The implementation was inspired by `LiveData.asFlow()` which uses a `callbackFlow` and has similar logic but with different rules to confirm to `LiveData` behavior.
*
* @return A Flow<Boolean> that emits whenever the ObservableBoolean value changes
*/
fun ObservableBoolean.asFlow(): Flow<Boolean> = callbackFlow {
// Emit the current value immediately
trySend(get())
// Set up a callback to listen for changes
val callback = object : Observable.OnPropertyChangedCallback() {
override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
trySend(get())
}
}
// Register the callback
addOnPropertyChangedCallback(callback)
// Clean up when the flow is cancelled
awaitClose {
removeOnPropertyChangedCallback(callback)
}
}.distinctUntilChanged() // Only emit when the value actually changes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment