表示されたときに処理をする

DisposableEffect

DisposableEffectは、コンポーザブルの表示開始(入場)に合わせてリスナーの登録などを行い、非表示(退場)時にそれらを確実にクリーンアップ(破棄・解放)するための副作用APIです。

LaunchedEffectとは異なり、コルーチン(サスペンド関数)の実行はできませんが、画面が閉じられたときやキーが変わったときに必ず後処理(onDispose)を走らせることができます。 

🛠 基礎的な使い方

DisposableEffectの末尾には、必ず onDispose { ... } を記述する必要があります。 

@Composable
fun MyComponent(keyData: String) {
    // keyData が変更されるか、コンポーザブルが破棄されると実行される
    DisposableEffect(keyData) {
        // 1. コンポーザブル入場時、またはキー変更時の処理
        println("登録処理を実行: $keyData")

        // 2. 必ず末尾にクリーンアップ処理を記述
        onDispose {
            println("解放処理を実行: $keyData")
        }
    }
}

💡 代表的な2つのユースケース

1. ライフサイクルイベント(onResumeなど)を監視する

Androidの画面状態(Lifecycle.Event)を検知し、画面を離れる際にオブザーバーを正しく解除します。 

2. BroadcastReceiver などのリスナー登録と解除

システムイベントを検知するレシーバーを登録し、アプリの画面が切り替わるタイミングで解除してメモリリークを防ぎます。 

⚠️ 知っておくべき仕様と注意点

  • onDispose の強制: ブロックの最後に onDispose を記述しないと、コンパイルエラーになります。
  • キー(Key)の再実行ルール: 引数に渡した key の値が変わると、古い onDispose が実行されてクリーンアップされ、新しい値で再度初期化処理が実行されます。
  • 一度だけ実行したい場合: 画面表示から消滅まで1度だけ登録・解除したい場合は、DisposableEffect(Unit)のように定数をキーに指定します。
  • 最新の状態を参照したい場合: エフェクト内で最新の引数やStateを参照しつつ、エフェクト自体は再起動させたくない場合は、rememberUpdatedState と組み合わせて使用します。 

付ける位置はColumnとかの中

LaunchedEffect

Jetpack Composeの LaunchedEffect は、コンポーザブルのライフサイクルに合わせて安全に非同期処理(コルーチン)を実行するための副作用(Side-Effect)APIです

通常のコンポーザブル関数は再コンポジション(画面更新)によって何度も実行されるため、ネットワーク通信や画面遷移などの処理を直接書くと意図しない無限ループや重複処理が発生します。LaunchedEffect を使うことで、これらの処理を適切に制御できます。

💡 主な効果と特徴

  • コルーチンスコープの自動生成
  • ライフサイクルに連動したキャンセル
  • キー(Key)による実行制御

🛠 基本的な使い方(パターン別)

1. 画面表示時に「1度だけ」実行したい場合(初期化など)

画面の初回表示時(Composition時)のみ実行し、その後の再コンポジションでは実行させない場合は、キーに Unit や true などの固定値を指定します。

2. 特定の状態が変化した時に「再実行」したい場合

状態(State など)をキーに渡すと、その値が変わるたびに内部のコルーチンがリスタートします。

3. 1回限りのイベント(One-shot Event)を検知して処理する場合

ViewModelからの画面遷移の指示や、スナックバーの表示要求をUI側で受け取る際によく使われます。

⚠️ 使用する際の注意点

  • 重い処理を直接書かない
  • ブロック内で使う変数はキーに含める

使い分け方

LaunchedEffect と DisposableEffect の最大の違いは、「非同期処理(コルーチン)を実行したいか」それとも「クリーンアップ(後処理)が必要な処理を行いたいか」です。

一言で言えば、「やりっぱなし(自動キャンセル任せ)でいいなら LaunchedEffect」、「自分で後始末(リスナーの解除など)が必要なら DisposableEffect」と使い分けます。

📊 比較一覧

項目LaunchedEffectDisposableEffect
主な目的非同期処理、サスペンド関数の実行リスナーの登録・解除、ライフサイクル連動
コルーチン利用できる(ブロックがサスペンドスコープ)利用できない(非同期処理は書けない)
クリーンアップ自動(画面消滅時にコルーチンがキャンセル)必須(onDispose ブロックの記述が強制)

🛠 2つの使い分けパターンと具体例

1. LaunchedEffect を使うべきケース(非同期・やりっぱなし)

コンポーザブルの消滅時に、実行中の処理(通信やアニメーションなど)が自動でキャンセルされればそれで十分な場合に使います。

  • 例:画面表示時のAPI通信、タイマーカウント、アニメーションの開始

2. DisposableEffect を使うべきケース(後始末が必須)

Androidシステムや外部ライブラリに対して、「登録(Subscribe)」と「解除(Unsubscribe)」をペアで行う必要がある場合に使います。
※末尾に onDispose { ... } の記述が必須(コンパイルエラーになります)。

  • 例:イベントリスナーの追加/削除、BroadcastReceiverの登録/解除、センサーの監視、ライフサイクルイベントの監視

⚠️ よくある間違い

DisposableEffect の中で非同期処理(コルーチン)を行おうとして、自前の CoroutineScope を作って起動(launch)するコードを見かけることがありますが、これはアンチパターンです。
画面消滅時(onDispose)に手動でコルーチンをキャンセルするコードを書くくらいなら、最初から LaunchedEffect を使用してください。

タイトルとURLをコピーしました