RxBinding
今日のAndroid開発では、MVI、Redux、一方向データフローなどの概念がますます導入されており、reactなどのフロントエンドフレームワークのような応答性の高いUI開発エクスペリエンスの実現に努めています。
Jetpack Composeのような急進的なソリューションに目を向けるだけでなく、クライアントにはRxBindingなどのローカル条件に合わせたソリューションもいくつかあります。RxJavaとAndroid Viewの連携により、Observableを使用してOnClickListenerを置き換え、イベント駆動型UI開発をより効率的に実現します。
findViewById<Button>(R.id.button).clicks().subscribe {
// handle button clicked
}
FlowBinding
kotlinx.coroutinesは、1.3以降にFlowライブラリを追加しました。これは、RxJavaのcoroutineバージョンと呼ばれるCoroutineScopeでストリーミングデータを応答的に処理できます。これに対応して、RxJava => Flowの優れたプロジェクトが数多くあります。本日紹介されたFlowBindingは、その1つであるRxBindingのFlowバージョンです。
// 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}"
FlowBindingは、Android標準コントロールに加えて、AndroidXおよびマテリアルコントロールのさまざまなコントロールもサポートします。
指示
CoroutineScopeでOnClickイベントを監視します。
uiScope.launch {
findViewById<Button>(R.id.button)
.clicks() // this returns a Flow<Unit>
.collect {
// handle button clicked
}
}
kotlinx-coroutines-core
表現launchIn(scope)
を単純化するために提供されていscope.launch { flow.collect() }
ます。
findViewById<Button>(R.id.button)
.clicks() // binding API available in flowbinding-android
.onEach {
// handle button clicked
}
.launchIn(uiScope)
上記の例のuiScopeは、アクティビティ/フラグメントのライフサイクルと一致するCoroutineScopeを表しており、メモリリークを効果的に回避します。
実際の開発では、androidx.lifecycle:lifecycle-runtime-ktx:2.2.0
提供されている拡張属性を使用LifecycleOwner.lifecycleScope: LifecycleCoroutineScope
でき、ライフサイクルonDestroyのスコープ内でコルーチンをキャンセルできます。
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
}
}
実施原則
実現の原則は比較的単純です。
scope.launch {
findViewById<Button>(R.id.button)
.clicks() // this returns a Flow<Unit>
.collect {
// handle button clicked
}
}
パスcallbackFlow
、コールバックをフローに変換して上記のclicks()
メソッドを実装できます
fun View.clicks(): Flow<Unit> = callbackFlow
val listener = View.OnClickListener {
offer(Unit)
}
setOnClickListener(listener)
awaitClose {
setOnClickListener(null) }
}
awaitClose{}
フローの最後に実行されるため、ここで登録を解除して
offer()
、SendChannel
フローの内部使用にデータを送信できますが、フローが閉じている場合、例外がスローされる可能性があるため、例外キャプチャ処理を増やすことができます。
fun <E> SendChannel<E>.safeOffer(value: E) = !isClosedForSend && try {
offer(value)
} catch (e: CancellationException) {
false
}
全体のコードは次のとおりです。
やっと
FlowBindingは、Coroutine Flowを使用して応答性の高いUIツールライブラリのセットを作成し、LifecycleScopeと連携して自動ログアウトを実現し、メモリリークを回避します。現在、Kotlinが普及している場合は、RxBindingの代わりにFlowBindingを使用することをお勧めします。これを機会として、RxJavaの代わりにFlowを使用するためのより多くの使用シナリオを検討してください。