Jetpack ComposeのButtonのonClickなど、イベントのコールバック関数内で時間のかかる処理をしたい場合は、rememberCoroutineScope()
を使います。起動したコルーチンを停止する方法も説明します。
やりたいこと
例として、一定時間内にボタンが3回タップされたかどうかを判定する、トリプルタップボタンを作成します。ボタンタップ時の処理はButton
のonClick
コールバックに処理を書くので、このコールバック関数内でコルーチン (Coroutnie) を呼び出す必要があります。また、条件によってコルーチンをキャンセルする必要もあります。
環境
- Kotlin 1.6.10
- Jetpack Compose 1.1.1
- Material3 1.0.0-alpha12
ソースコードと説明
TripleTapButton()
は、Button()
をラップし、トリプルタップが成立したらonTripleTap()
をコールバックする関数です。
@Composable
fun TripleTapButton(onTripleTap: ()->Unit, content: @Composable RowScope.()->Unit) {
val scope = rememberCoroutineScope()
var job: Job? = remember{ null }
var tapCount = remember { 0 }
Button(
onClick = {
if (tapCount == 0) {
job = scope.launch {
delay(1000)
tapCount = 0
}
}
tapCount++
if (tapCount >= 3) {
job?.cancel()
onTripleTap()
tapCount = 0
}
},
content = content
)
}
rememberCoroutineScope
コルーチンを起動するためのスコープは、rememberCoroutineScope()
で取得します。rememberCoroutineScope()
で取得したCoroutineScope
は、最初のコンポジションで作成され、再コンポジションが走っても保持されます。そして、コンポジションから退出するタイミングで、実行中のコルーチンをキャンセルして削除されます。
注意すべきポイントは、rememberCoroutineScope()
で作成したCoroutineScope
を使えるのは、コンポーザブルではなく普通のUIスレッドだということです。つまり、onClick
などのコールバック関数内でコルーチンを使いたいときに、rememberCoroutineScope()
を使います。
ちなみに、コンポーザブルでコルーチンを使いたい場合は、LaunchedEffect
を使います。
コルーチンを起動する
トリプルタップの判定のために、最初のタップから一定時間以内のタップ数をカウントします。そこで、最初のタップ発生時に、rememberCoroutineScope()
で取得したCoroutineScope
に対してlaunch()
を呼び出して、コルーチンを起動します。launch()
の戻り値はJob
です。これはあとでキャンセルするときのために、remember
変数で保持しておきます。
コルーチン内では、delay()
を使い、一定時間後にタップ数をゼロに戻すという処理をしています。これが実行されたときは、トリプルタップが成立しなかったということになります。
コルーチンをキャンセルする
onClick
は、呼ばれるたびにタップ数をインクリメントします。コルーチン内の処理によってタップ数がゼロにリセットされるより早く、タップ数が3に到達すれば、トリプルタップ成立です。トリプルタップが成立したら、起動中のコルーチンをキャンセルしなければなりません。コルーチンのキャンセルは、launch()
の戻り値として取得したJob
に対してcancel()
を呼び出すことで可能です。
トリプルタップが成立したら、コルーチンをキャンセルし、TripleTapButton()
のコールバック関数を呼び出し、タップ数をゼロにリセットしています。
まとめ
Jetpack Composeでコルーチンを使う方法はいくつかのバリエーションがあって、最初は難しく感じるのですが、もっともシンプルな使い方としては、コンポーザブル内で使う場合はLaunchedEffect()
、コールバック関数内で使う場合はrememberCoroutineScope()
と考えておけばよいです。
余談ですが、Androidのボタンなどのコンポーネントを「タップ」した時のイベントがon”Click”と呼ぶことにいつも違和感を感じます。英語ではあまり”tap”と言わないのでしょうか。
コンテンツは随時追加していきます。