Last active
August 29, 2025 19:51
-
-
Save levibostian/7002a0146e2b217bbd1f710e85a09cab to your computer and use it in GitHub Desktop.
android databinding ObservableBoolean to Kotlin Coroutine Flow
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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