Lifecycleでライフサイクル対応コンポーネント作成

投稿日:  更新日:

Androidアーキテクチャコンポーネント(AAC)は「堅牢でテストとメンテナンスが簡単なアプリの設計を支援する」とドキュメントで説明されています。

その中で紹介されているコンポーネントの1つが「Lifecycle」です。

Lifecycleについて、まとめました。

スポンサーリンク

ラフサイクル対応コンポーネントとは

画面の表示制御以外にも、Activityのライフサイクルに連動させたい処理があります。

例えば、

  センサーは画面の表示中のみ動作させればバッテリー容量の節約になる。
  onStartで起動、onStopで停止すればよい。

  レシーバは画面の表示中のみ受信させればプロセッサ資源の節約になる。
  onStartでレシーバを登録、onStopで解除するばよい。

などです。

このような処理が多くなると、ライフサイクル中に雑多な処理が集中して、プログラムの見通しが悪くなります。

Activity以外の処理がライフサイクル中に集中

Lifecycleを実装すると、Activityがシステムから受け取るコールバックの起動イベント(図中のON_START,ON_STOP)を特定のクラスへ転送できるようになります。特定のクラス側はイベントを受け取って関数が起動できます。

これは「特定のクラスにライフサイクルを持たせる」ことを示します。このようなクラスを「ライフサイクル対応コンポーネント」と呼びます。

ライフサイクル対応コンポーネントで処理を分離

ラフサイクル対応コンポーネントがあれば、Activityのライフサイクル中に処理を置く必要はありません。代わりにコンポーネントのライフサイクル中へ置けば良いのです。

Activityは画面の表示のみに専念でき、プログラムがスッキリします。

スポンサーリンク

Lifecycleの実装(イベントを転送する)

Lifecycleを実装してイベントを転送するためには、次の3つが必要です。

 (1)LifecycleOwnerインターフェースを実装
 (2)イベントの転送処理
 (3)イベントの受信クラスの登録

Activityがandroidx.appcompat.app.AppCompatActivityを継承していれば、すでに(1)と(2)は実施済みです。特に何もする必要はなく、イベントが転送できる状態になっています。

Activityのクラス図

(3)は後述します。

参考:(1)LifecycleOwnerインターフェースを実装、(2)イベントの転送処理

あえて、ActivityへLifecycleの実装を行うとすれば、以下のようになります。

ただし、イベントは転送されますが、イベント転送のタイミングはAppCompatActivityのように調整されません。

public interface LifecycleOwner {
    @NonNull
    Lifecycle getLifecycle();
}
import android.app.Activity

class MyActivity : Activity(), LifecycleOwner {

    private val lifecycleRegistry = LifecycleRegistry(this)
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
		...            // ↑(2)イベントの転送処理↑ この時点でイベント転送
    }

    override fun onStart() {
        super.onStart()
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
		...            // ↑(2)イベントの転送処理↑ この時点でイベント転送
    }
	
	/* onResume/onPause/onStop/onDestroyも同様 */

    override fun getLifecycle(): Lifecycle = lifecycleRegistry
}
スポンサーリンク

コンポーネント作成(イベントを受信する)

ライフサイクル対応コンポーネントはLifecycleObserverインターフェースを実装します。

LifecycleObserverは抽象プロパティも抽象関数も持たない空のインターフェースです。このクラスがエベントを受信する対象になっている事を示します。マーキングの役割です。

関数へ@OnLifecycleEventアノテーションを付加して、イベントによって起動する関数であることを指定します。

class SampleComponent : LifecycleObserver{

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreate() {						// 引数なしタイプ
        // Createで行う処理
    }
    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreate(owner: LifecycleOwner) {	// LifecycleOwner引数あり合タイプ
        // Createで行う処理
    }
	
	/*
	** onStartも同様	Lifecycle.Event.ON_START
	** onResumeも同様	Lifecycle.Event.ON_RESUME
	** onPauseも同様	Lifecycle.Event.ON_PAUSE
	** onStopも同様	Lifecycle.Event.ON_STOP
	** onDestroyも同様	Lifecycle.Event.ON_DESTROY
	*/
}
public interface LifecycleObserver {

}

後は、「Lifecycle実装:(3)イベントの受信クラスの登録」で示したように、Lifecycle#addObserver( )を使ってコンポーネントを登録すれば、イベントが転送されるようになります。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
		
        lifecycle.addObserver(SampleComponent()) //(3)イベントの受信クラスの登録
		...
    }
	
	...
}
スポンサーリンク

ライフサイクルのEventsとStates

Lifecycleはライブサイクルの状態をEventとState列挙型で管理しています。

下図は状態の変化とタイミングを示しています。

ライフサイクルのEventsとStates

ライフサイクル対応コンポーネントに転送されるEventの発火とStateの変化は同時に起こります。

StateはLifecycleから取得できるので条件判断に役立ちます。
※後述「すべてに適合するイベント」を参照

スポンサーリンク

すべてに適合するイベント(ON_ANY)

ON_ANYイベントはすべてに適合するイベントです。

よって、@OnLifecycleEventアノテーションにON_ANYが指定されている関数は、すべてのEventで実行されます。

class SampleComponent : LifecycleObserver{

    @OnLifecycleEvent(Lifecycle.Event.ON_ANY)	// すべてのイベントを受信
    fun onAny() {
        // すべてのEventで行う処理
    }
	
    @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
    fun onAny(owner: LifecycleOwner) {
        when(owner.lifecycle.currentState) {	// LifecycleからStateを取得
            Lifecycle.State.STARTED, Lifecycle.State.RESUMED -> { 
                // STARTEDとRESUMEDで行う処理
            }
            else -> {
                // その他のStateで行う処理
            }
        }
    }
	
    @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
    fun onAny(owner: LifecycleOwner, event: Lifecycle.Event) {
        when(event) {
            Lifecycle.Event.ON_START, Lifecycle.Event.ON_RESUME -> {
                // ON_STARTとON_RESUMEで行う処理
            }
            else -> {
                // その他のEventで行う処理
            }
        }
    }
}
スポンサーリンク

コンポーネントを複数登録

複数のコンポーネントにイベントを転送したい場合は、コンポーネントの数だけLifecycle#addObserver( )を実行すればよいです。

ただし、登録した順番にイベントが転送されます。

class AAA_Sensor : LifecycleObserver {
	...
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onStart() {
        Log.i(TAG, "onStart Start")
        // センサーの起動
        Log.i(TAG, "onStart End")
    }
	/* onStopも同様	Lifecycle.Event.ON_STOP */
	...
}
class BBB_Sensor : LifecycleObserver {
	...
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onStart() {
        Log.i(TAG, "onStart Start")
        // センサーの起動
        Log.i(TAG, "onStart End")
    }
	/* onStopも同様	Lifecycle.Event.ON_STOP */
	...
}
class CCC_Receiver : LifecycleObserver {
	...
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onStart() {
        Log.i(TAG, "onStart Start")
        // レシーバの登録
        Log.i(TAG, "onStart End")
    }
	/* onStopも同様	Lifecycle.Event.ON_STOP */
	...
}
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        lifecycle.addObserver(AAA_Sensor())
        lifecycle.addObserver(BBB_Sensor())
        lifecycle.addObserver(CCC_Receiver())
    }

    override fun onStart() {
        super.onStart()
        Log.i(TAG, "onStart Start state=${lifecycle.currentState}")
        Thread.sleep(100)
        Log.i(TAG, "onStart End state=${lifecycle.currentState}")
    }
	/* onStopも同様 */	
	...
}
[ アプリを起動 ]
I/MainActivity: onStart Start state=CREATED
I/MainActivity: onStart End state=CREATED
I/AAA_Sensor: onStart Start
I/AAA_Sensor: onStart End
I/BBB_Sensor: onStart Start
I/BBB_Sensor: onStart End
I/CCC_Receiver: onStart Start
I/CCC_Receiver: onStart End
[ アプリを終了 ]
I/CCC_Receiver: onStop Start
I/CCC_Receiver: onStop End
I/BBB_Sensor: onStop Start
I/BBB_Sensor: onStop End
I/AAA_Sensor: onStop Start
I/AAA_Sensor: onStop End
I/MainActivity: onStop Start state=CREATED
I/MainActivity: onStop End state=CREATED
スポンサーリンク

関連記事:

Androidアーキテクチャコンポーネント(AAC)は「堅牢でテストとメンテナンスが簡単なアプリの設計を支援する」とドキュメントで説明されています。 有効そうだけど、実態がよくわからないので、いろいろ調べて理解した内容をまとめました。 ...
Androidアーキテクチャコンポーネント(AAC)は「堅牢でテストとメンテナンスが簡単なアプリの設計を支援する」とドキュメントで説明されています。 その中で紹介されているコンポーネントの1つが「LiveData」です。 LiveDataについて、まとめました。 ...
Androidアーキテクチャコンポーネント(AAC)は「堅牢でテストとメンテナンスが簡単なアプリの設計を支援する」とドキュメントで説明されています。 その中で紹介されているコンポーネントの1つが「ViewModel」です。 ViewModelについて、まとめました。 ...
Androidの開発スピードが速過ぎます。個人で習得を進めている私には、追い付いて行けません。 これが会社などであれば、グループ内のメンバーで分担して習得し、後に共有、などといった対応が可能でしょう。組織の強みですね! 先日も、久しぶりにAndroid Studioで新規プロジェクトを作成したら、Jetpack Composeのプロジェクトになってました。「はて?、これはどうすれば良いのだ?」と、頭の中は疑問符だらけで、プログラミングが先へ進めませんでした。 Jetpackの存在は知りながら、“使わなくてもアプリは作れる”と、学習は後回していたからです。 プロジェクトのひな型にJetpack Composeが採用されたならば、今後はJetpackの利用が開発の主軸になっていくのでしょう。 遅れ馳せならが、Jetpackの重要性を知った次第です。 ここで本腰をいれて習得しないと、さらに後方へ置いて行かれそうです。 という訳で、Jetpackの学習を始めました。 今回はJetpackそのものについてまとめます。 ※環境:Android Studio Flamingo | 2022.2.1 ...
スポンサーリンク