dropUnlessResumedとdropUnlessStartedの解説

Kenji Abe
4 min readFeb 23, 2024
Photo by Glen Carrie on Unsplash

lifecycle-runtime-compose 2.8.0-alpha02 から dropUnlessResumeddropUnlessStarted というのが追加されています。これがどういったものかと使用例について解説します。

⚠️ まだalphaなので今後変更されることがあります。

dropUnlessResumed / dropUnlessStarted

まず単純な使い方としては以下のようになります。 Composable関数になっているので、Composable関数からしか使用できません。

val resumed = dropUnlessResumed {
// do something
}
resumed.invoke()

val started = dropUnlessStarted {
// do something
}
started.invoke()

この2つは現在のライフサイクルが少なくても RESUMED または STARTED の状態のときのみブロック内が実行されるものになります。
これはすぐに実行されるものではなく、戻り値として () -> Unit が返されるので、それを呼び出すことで実行されます。

実際には以下のように ButtononClick などに対して設定することになると思います。

Button(
onClick = dropUnlessResumed {
// do something
}
) {
Text(text = "Test")
}

実装

実際の中身の実装としては現在のLifecycleから Lifecycle.State#isAtLeast でチェックして実行するかどうか制御してるだけでした。

引数には任意で LifecycleOwner を指定することもできます。

使い所

もっとも有効な使い所としては、画面遷移と組み合わせる方法になります。

その前にまずはComposeの画面遷移の問題点に簡単に解説しておきます。

画面遷移の問題点

例えば、以下のように画面遷移を行う2つのボタンがあったとします。

Button(
onClick = {
navController.navigate("next1")
}
) {
Text(text = "Next 1")
}

Button(
onClick = {
navController.navigate("next2")
}
) {
Text(text = "Next 2")
}

このときに2本の指を使い、同時に2つのボタンを押したらどうなるでしょうか?

この場合は、どちらのボタンも実行され画面遷移が2度行われることになります。こおそらく多くの開発者は想定していない挙動だと思います。

既存の対応方法

これに対しては一応は自前でLifecycleを遷移前にチェックすることで対応することができます。

compose-samples で使用されています。

dropUnlessResumed / dropUnlessStarted を使った対応

今回新しく追加されたこの2つを使って同じような対応をすることができます。 navigate メソッドをこちらを使って呼び出すようにするだけです。

Button(
onClick = dropUnlessResumed { // dropUnlessResumedを使うことで重複して画面遷移しない
navController.navigate("next1")
}
) {
Text(text = "Next 1")
}

まだ正式なドキュメントは公開されてないですが、コード上のコメントで画面遷移時に使用することを推奨しています。

For Navigation users, it’s recommended to safeguard navigate methods when using them while a composable is in transition as a result of navigation.

--

--

Kenji Abe

Programmer / Gamer / Google Developers Expert for Android, Kotlin / @STAR_ZERO