Binding Android UI with Kotlin Flow

findViewById<Button>(R.id.button).clicks().subscribe {
// handle button clicked
}

Kotlin Flow

Binding Android UI with Flow

scope.launch {
findViewById<Button>(R.id.button)
.clicks() // this returns a Flow<Unit>
.collect {
// handle button clicked
}
}
fun View.clicks(): Flow<Unit> = callbackFlow 
val listener = View.OnClickListener {
offer(Unit)
}
setOnClickListener(listener)
awaitClose { setOnClickListener(null) }
}
fun <E> SendChannel<E>.safeOffer(value: E) = !isClosedForSend && try {
offer(value)
} catch (e: CancellationException) {
false
}
@CheckResult
@UseExperimental(ExperimentalCoroutinesApi::class)
fun Slider.valueChanges(emitImmediately: Boolean = false): Flow<Float> = callbackFlow {
checkMainThread()
val listener = Slider.OnChangeListener { _, value ->
safeOffer(value)
}
setOnChangeListener(listener)
awaitClose { setOnChangeListener(null) }
}
.startWithCurrentValue(emitImmediately) { value }
.conflate()
fun <T> Flow<T>.startWithCurrentValue(emitImmediately: Boolean, block: () -> T?): Flow<T> {
return if (emitImmediately) onStart {
block()?.run { emit(this) }
}
else this
}

Introducing FlowBinding

// Platform bindings
implementation "io.github.reactivecircus.flowbinding:flowbinding-android:${flowbinding_version}"
// AndroidX bindings
implementation "io.github.reactivecircus.flowbinding:flowbinding-appcompat:${flowbinding_version}"
implementation "io.github.reactivecircus.flowbinding:flowbinding-core:${flowbinding_version}"
implementation "io.github.reactivecircus.flowbinding:flowbinding-drawerlayout:${flowbinding_version}"
implementation "io.github.reactivecircus.flowbinding:flowbinding-navigation:${flowbinding_version}"
implementation "io.github.reactivecircus.flowbinding:flowbinding-recyclerview:${flowbinding_version}"
implementation "io.github.reactivecircus.flowbinding:flowbinding-swiperefreshlayout:${flowbinding_version}"
implementation "io.github.reactivecircus.flowbinding:flowbinding-viewpager2:${flowbinding_version}"
// Material Components bindings
implementation "io.github.reactivecircus.flowbinding:flowbinding-material:${flowbinding_version}"

Tests

Usage

findViewById<Button>(R.id.button)
.clicks() // binding API available in flowbinding-android
.onEach {
// handle button clicked
}
.launchIn(uiScope)

Binding Scope

class ExampleActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_example)
findViewById<Button>(R.id.button)
.clicks()
.onEach {
// handle button clicked
}
.launchIn(lifecycleScope) // provided by lifecycle-runtime-ktx

}
}

Roadmap

--

--

--

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

How i was able to bypass parental pin of showmax

Monthly Progress Report

Run Bolt with Docker and Terraform with Alibaba Cloud

Drone CI/CD with Packer + Ansible

GDG DevFest Ukraine 2017: key notes

Fishfactory Protocol: Update on EarlyBirds Test Fishfarming Conscription.

Gutenberg — First Impressions

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Yang

Yang

More from Medium

Android 13: Notification Runtime Permission

Jetpack Compose for Views developers — LinearLayout

BeeHive View in Android

Support for Split Application Binary (.OBB)