Jetpack ComposeのonClickでコルーチンを使いたい

この記事をシェア
JetpackCompose一問一答

Jetpack ComposeのButtonのonClickなど、イベントのコールバック関数内で時間のかかる処理をしたい場合は、rememberCoroutineScope()を使います。起動したコルーチンを停止する方法も説明します。

やりたいこと

例として、一定時間内にボタンが3回タップされたかどうかを判定する、トリプルタップボタンを作成します。ボタンタップ時の処理はButtononClickコールバックに処理を書くので、このコールバック関数内でコルーチン (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”と言わないのでしょうか。

JetpackCompose一問一答

Jetpack Compose一問一答

コンテンツは随時追加していきます。

この記事をシェア