repeatOnLifecycleとlaunchWhenXX
ActivityやFragmentでFlowをcollectする際にrepeatOnLifecycle
やlaunchWhenResume
などを利用しているコードがよくあると思います。
この2つのメソッドの違いと使い所を見ていきます。
注意
後述もしますがlaunchWhenXX
は削除予定とされていて、挙動としてもFlowをcollectするには向かないためrepeatOnLifecycle
を利用することをオススメします。
特徴
launchWhenXX
launchWhenXX
には以下の3種類があります。
launchWhenCreated
launchWhenResumed
launchWhenStarted
これらのメソッドの挙動としては
- 引数で渡している処理の実行を指定したライフサイクルになるまで延期
- 指定したライフサイクルになったタイミングで処理が開始され、その指定されたライフサイクルに対応したライフサイクルになると処理が中断
- 再度指定したライフサイクルになった場合に処理が再開
となっています。
例としてlaunchWhenStarted
の場合
- Activity/Fragmentが
STARTED
になると処理を開始 - Activity/Fragmentが
STOPED
になると処理を中断 - 再度Activity/Fragmentが
STARTED
になると処理を再開
といった流れになります。
同じ挙動を行うものとしてLifecycleOwner?.whenXX
といったメソッドがあります。
こちらもwhenCreated/whenResumed/whenStarted
といった3種類あります。
またlaunchWhenXX
のメソッドは削除予定とされていて、whenXX
に関しては何も言及されていないため、Flowをcollectする以外で同様の挙動を利用したい場合は代わりにこちらを使うと良さそうです。
repeatOnLifecycle
repeatOnLifecycle
は種類があるわけではなく、repeatOnLifecycle(Lifecycle.STARTED)
のようにすることで処理を開始するライフサイクルを指定することができます。
repeatOnLifecycle
もlaunchWhenXX
と同様に指定したライフサイクルで処理を開始したり特定のライフサイクルで止めたりするものです。
この記事を書くために調べるまで知らなかったのですが、lifecycle-runtime-ktx:2.4.0-alpha01
で導入されたflowWithLifecycle
というものがあります。
こちらもLifecycle.State
を渡すことでrepeatOnLifecycle
と同様な挙動を実現できそうです。
flowWithLifecycle
はインデントを減らせますが、複数のFlowをcollectする場合はrepeatOnLifecycle
の方がまとめやすいためケースや開発方針でどちらを利用するか選択すると良さそうです。
違い
launchWhenXX
とrepeatOnLifecycle
の違いとして、特定のライフサイクルになった時の停止・再開の挙動が異なります。
launchWhenXX
はSTOPED
などの特定のライフサイクルになった場合は実行中の処理を中断、再度STARTED
などになった時はその処理を再開します。
それに対し、repeatOnLifecycle
はSTOPED
などの特定ライフサイクル時に処理をキャンセル、再度STARTED
などになった時は処理を最初から実行し直します。
この違いからFlowのcollectする際はrepeatOnLifecycle
を利用することが公式からも推奨されています。
ただ、repeatOnLifecycle
は指定したライフサイクルになるたびに処理を最初から実行するため、特定のライフサイクル時に一度だけ処理を実行したいといったケースのには向いていないです。
そういった際は、LifecycleOwner?.whenXX
を利用すると良さそうです。
もう少し深掘り
では、なぜrepeatOnLifecycle
の方が良いのかというと、launchWhenXX
ではSTOPED
になった場合に処理が中断されSTARTED
になった際に再開されるためcoroutineの処理が残り続けることになります。
このようにcoroutineが残っていることによって、STOPED〜STARTED
の間のバックグラウンドにある状態でもFlowがアクティブのままになり新しいアイテムが流れる可能性があったりリソースの浪費に繋がってしまったりします。
そのため、Flowをcollectする際はrepeatOnLifecycle
の利用が推奨されています。
まとめ
まとめとしては以下のような使い分けになります。
Flowをcollectしたい! → repeatOnLifecycle
一度きり(ショットな)suspend処理を実行したい! → whenXX
参考
Discussion