【Android】LifecycleOwner として Fragment 自身ではなく viewLifecycleOwner を使うべき場合

`Fragment` クラスは `LifecycleOwner` インターフェイスを実装しています。
しかし `LifecycleOwner` オブジェクトとして、`Fragment` オブジェクト自身ではなく、
`Fragment.viewLifecycleOwner` プロパティが返すオブジェクトを使うべき場合があります。

本稿では、まず前提となる ライフサイクル、`Lifecycle` クラス、`LifecycleOwner` インターフェイス について簡単に説明してから、その本題について説明します。


## ライフサイクル

アクティビティやフラグメントにはライフサイクルがあります。

![アクティビティのライフサイクル](https://developer.android.com/guide/components/images/activity_lifecycle.png?hl=ja "アクティビティのライフサイクル") ![フラグメントのライフサイクル](https://developer.android.com/static/images/fragment_lifecycle.png?hl=ja "フラグメントのライフサイクル")

画像は以下より。
- [アクティビティのライフサイクルについて  \|  Android デベロッパー  |  Android Developers](https://developer.android.com/guide/components/activities/activity-lifecycle?hl=ja)
- [フラグメント  \|  Android デベロッパー  |  Android Developers](https://developer.android.com/guide/components/fragments?hl=ja)


## `Lifecycle` クラス

[`Lifecycle` クラス](https://developer.android.com/reference/kotlin/androidx/lifecycle/Lifecycle?hl=ja)はアクティビティやフラグメントのライフサイクルを表します。

[`Lifecycle.addObserver(LifecycleObserver)` 関数](https://developer.android.com/reference/kotlin/androidx/lifecycle/Lifecycle?hl=ja#addObserver(androidx.lifecycle.LifecycleObserver))を用いることで、以下のライフサイクルイベントを監視することができます。

| ライフサイクルイベント | 発行タイミング |
| ---------------------- | -------------- |
| `ON_CREATE`              | `onCreate` の後  |
| `ON_START`               | `onStart` の後   |
| `ON_RESUME`              | `onResume` の後  |
| `ON_PAUSE`               | `onPause` の前   |
| `ON_STOP`                | `onStop` の前    |
| `ON_DESTORY`             | `onDestory` の前 |

## `LifecycleOwner` インターフェイス

`Lifecycle` オブジェクトは [`LifecycleOwner` インターフェイス](https://developer.android.com/reference/kotlin/androidx/lifecycle/LifecycleOwner)の [`lifecycle` プロパティ](https://developer.android.com/reference/kotlin/androidx/lifecycle/LifecycleOwner#getLifecycle())から取得できます。
`Activity` クラスや `Fragment` クラスは `LifecycleOwner` インターフェイスを実装しています。

```plantuml
interface LifecycleOwner {
    lifecycle: Lifecycle
}

LifecycleOwner::lifecycle -> Lifecycle

LifecycleOwner <|.. Activity
LifecycleOwner <|.. Fragment
```


## ライフサイクルイベントを監視する主要な API

次のような API は `Lifecycle` オブジェクトが発行するライフサイクルイベントを監視して動作の変更を行います。

| API                                                                                                                                                                                                                                                                                                                                                                          | 説明                                                                          |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| [`Lifecycle.coroutineScope` プロパティ](https://developer.android.com/reference/kotlin/androidx/lifecycle/Lifecycle#(androidx.lifecycle.Lifecycle).coroutineScope())<br>[`LifecycleOwner.lifecycleScope` プロパティ](https://developer.android.com/reference/kotlin/androidx/lifecycle/LifecycleOwner#(androidx.lifecycle.LifecycleOwner).lifecycleScope())[^lifecycleScope] | `ON_DESTORY` イベントでキャンセルされる `CoroutineScope` オブジェクトを返す。 |
| [`LiveData.observe(LifecycleOwner, Observer<Object>)` 関数](https://developer.android.com/reference/androidx/lifecycle/LiveData#observe(androidx.lifecycle.LifecycleOwner,androidx.lifecycle.Observer%3C?%20super%20T%3E))                                                                                                                                                   | `LiveData` オブジェクトの監視を開始する。`ON_DESTORY` イベントで解除される。  |

[^lifecycleScope]: `LifecycleOwner.lifecycleScope` プロパティは内部で `Lifecycle.coroutineScope` プロパティを呼んでいる。

他にも色々あるはずですが、
不要になったら自動で解除するようなものは基本的に
`ON_DESTROY` イベントで解除すると考えられます。


## フラグメントのライフサイクルの問題

フラグメントのライフサイクルを再度確認してみましょう。

![フラグメントのライフサイクル（再掲）](https://developer.android.com/static/images/fragment_lifecycle.png?hl=ja "フラグメントのライフサイクル（再掲）")

フラグメントでは `onDestory` に行かず `onCreateView` に戻る流れがあります。

つまり、`onCreateView` や `onActivityCreated` などのライフサイクル関数で開始した処理
を `ON_DESTROY` イベントで解除しようとしていると、
解除していないのに再度開始してしまうことが起こります。

例えば `onCreateView` で `LiveData.observe` 関数を呼び出した場合だと、値が変更された時の処理が多重に呼ばれることになります。


## `Fragment.viewLifecycleOwner` プロパティで解決

この問題を解決するのが [`Fragment.viewLifecycleOwner` プロパティ](https://developer.android.com/reference/kotlin/androidx/fragment/app/Fragment?hl=ja#getViewLifecycleOwner())です。

このプロパティは `LifecycleOwner` オブジェクトを返しますが、
それは `Fragment` クラスが実装しているものとは異なります。

```plantuml
interface LifecycleOwner {
    lifecycle: Lifecycle
}
class Fragment {
    viewLifecycleOwner: LifecycleOwner
}
class FragmentViewLifecycleOwner
note top: 非公開のクラス

LifecycleOwner <|.. Activity
LifecycleOwner <|.. Fragment
LifecycleOwner <|.. FragmentViewLifecycleOwner

LifecycleOwner::lifecycle -> Lifecycle
Fragment::viewLifecycleOwner -> FragmentViewLifecycleOwner

Activity -[hidden] Fragment
```

この `LifecycleOwner` オブジェクトの `lifecycle` プロパティが返す `Lifecycle` オブジェクトは、`ON_CREATE` イベントと `ON_DESTROY` イベントの発行タイミングが次のようになります。（他の4イベントは同じです。）

| ライフサイクルイベント | 発行タイミング |
|---|---|
| `ON_CREATE` | `onViewStateRestored` の後（`onCreateView` より後） |
| `ON_DESTROY` | `onDestroyView` の前 |

そのため `onCreateView` から `onViewStateRestored` までの間に開始した処理を
`onDestroyView` で解除することができ、
すなわち `onDestory` が呼ばれずに再度 `onCreateView` が呼ばれても、多重に実行されるということがないようにできます。

![フラグメントのライフサイクル（詳細版）](https://image.itmedia.co.jp/ait/articles/1604/04/android_jitsumu2_8.jpg "フラグメントのライフサイクル（詳細版）")

画像は下記より。Android 公式の図より細かくなっています。
- [知らずに作って大丈夫？Androidの基本的なライフサイクルイベント31選：実業務でちゃんと使えるAndroidアプリ開発入門（2）（3/4 ページ） - ＠IT](https://atmarkit.itmedia.co.jp/ait/articles/1604/04/news011_3.html)


## まとめ

`Fragment` オブジェクト自身を `LifecycleOwner` として使うと問題がある場合があります。
代わりに `Fragment.viewLifecycleOwner` プロパティが返す `LifecycleOwner` オブジェクトを使用することを検討しましょう。

`Fragment.viewLifecycleOwner` プロパティを使うべきなのは、
`onCreateView` もしくはそれ以降のライフサイクル関数で開始した処理を `ON_DESTROY` イベントで解除する場合です。

また、`LifecycleOwner` の[拡張関数](https://developer.android.com/reference/kotlin/androidx/lifecycle/LifecycleOwner#extension-functions_1)・[拡張プロパティ](https://developer.android.com/reference/kotlin/androidx/lifecycle/LifecycleOwner#extension-properties_1)を、そうと意識せず、`viewLifecycleOwner` プロパティから使うべき場合に `Fragment` オブジェクトから直接使ってしまわないようにも注意しましょう。


## 参考資料

https://satoshun.github.io/2018/12/view_lifecycle/

https://proandroiddev.com/5-common-mistakes-when-using-architecture-components-403e9899f4cb#2994

https://star-zero.medium.com/fragmentのlifecycleownerはgetviewlifecycleownerを使おう-3ab8b1d976ba

https://atmarkit.itmedia.co.jp/ait/articles/1604/04/news011_3.html

／以上