Channel を使ってコールバック不要に
Channel の定義 (JetBrains のドキュメントより):
Channel は、概念的に BlockingQueue とよく似ています。主な違いの一つは、Put の代わりに「送信中断」をを持ち、Take の代わりに「受信中断」を持つことです。
Actor
Channel をシンプルに使えるツールが Actor です。
Actor は Handler と非常によく似ており、コルーチンのコンテキスト(つまり、アクションを実行するスレッド)を定義し、シーケンシャルに実行します。
コルーチンを使っており、キャパシティを決めて実行を中断することができます。
Actor は基本的に、処理をコルーチンチャンネルに転送します。実行順序と実行するコンテキストを限定することを保証します。
これで、synchronize は不要となり、すべてのスレッドはフリーです。
protected val updateActor by lazy {
actor<Update>(UI, capacity = Channel.UNLIMITED) {
for (update in channel) when (update) {
Refresh -> updateList()
is Filter -> filter.filter(update.query)
is MediaUpdate -> updateItems(update.mediaList as List<T>)
is MediaAddition -> addMedia(update.media as T)
is MediaListAddition -> addMedia(update.mediaList as List<T>)
is MediaRemoval -> removeMedia(update.media as T)
}
}
}
// 使い方
suspend fun filter(query: String?) = updateActor.offer(Filter(query))
この例では、実行するアクションを選択する際、sealed クラスを利用しています。
sealed class Update
object Refresh : Update()
class Filter(val query: String?) : Update()
class MediaAddition(val media: Media) : Update()
すべてのアクションはキューとなり、決してパラレルには実行されません。mutable なものを密閉するにはいい方法です。
【Android】Kotlin でモダンな concurrency その1
【Android】Kotlin でモダンな concurrency その2
【Android】Kotlin でモダンな concurrency その3