【Kotlin研修5日目】フラグメントのライフサイクルおよび実装

# フラグメント
[参考: フラグメント](https://developer.android.com/guide/fragments)
`マルチデバイス対応`などで用いられる、`画面サイズ`に応じて`レイアウト`を変えられる仕組み。
端末の1画面を複数の`区画`に分割することで、各`区画`に複数の`フラグメント`画面を埋め込めるようにしている。
なお、`フラグメント`画面(=`Fragment`ファイル)は`アクティビティ`と同様、`レイアウトファイル`と`アクティビティ`で構成される。

## フラグメントのライフサイクル
`フラグメント`は、まず`フラグメント`を埋め込む`アクティビティ`と関連付けられ、
その後に`フラグメント`がもつ`ビュー`と関連付けられる。

### フラグメント⇄アクティビティのライフサイクル関係
![フラグメントのライフサイクル2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673880/4918ab2b-35ca-782f-40b7-d67ac06380ca.png)
[出典](https://developer.android.com/guide/components/fragments.html#Creating)

### フラグメント⇄ビューのライフサイクル関係
![フラグメントのライフサイクル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673880/70b526aa-78f9-7f43-2f22-863f4fd6d673.png)
[出典](https://developer.android.com/guide/fragments/lifecycle)

### ビュー⇄フラグメント⇄アクティビティのライフサイクル

|`フラグメント`|`ビュー`|`Fragment`メソッド|呼び出しタイミング|
|:--|:--|:--|:--|
|`Created`||`onAttach()`|`アクティビティ`との最初の関連付け|
|`Created`||`onCreate()`|`フラグメント`の`初期化`|
|`Created`|`Initialized`|`onCreateView()`|`ビューレイアウト`の`インフレート`<br>(=`ビュー`との関連付け)|
|`Created`|`Initialized`|`onViewCreated()`|`onCreateView()`の終了|
|`Created`|`Created`|`onActivityCreated()`|`アクティビティ`の生成完了、<br>`ビューレイアウト`の実体化完了<br>(=`Activity.onCreate()`)|
|`Created`|`Created`|`onViewStateRestored()`|保存済み`ビューUI`の復元完了|
|`Started`|`Started`|`onStart()`|`フラグメント`の表示<br>(=`Activity.onStart()`)|
|`Resumed`|`Resumed`|`onResume()`|`フラグメント`の操作受付完了<br>(=`Activity.onResume()`)|
|`Started`|`Started`|`onPause()`|`フラグメント`の一時停止<br>(=`Activity.onPause()`)|
|`Created`|`Created`|`onStop()`|`フラグメント`の停止<br>(=`Activity.onStop()`)|
|`Created`|`Created`|`onSaveInstanceState()`|`ビュー`の`UI状態`の保存|
|`Created`|`Destroyed`|`onDestroyView()`|`ビュー`との関連付け解除|
|`Destroyed`||`onDestroy()`|`フラグメント`の利用停止|
|`Destroyed`||`onDetach()`|`アクティビティ`との関連付け解除|

***

# フラグメントによる画面の実装
`フラグメント`を実装するには、`Fragment`ファイル(=`レイアウトファイル`と`アクティビティ`の組み合わせ)を作成する。

## レイアウトのインフレート(フラグメントの生成)

### 定義

```kotlin
LayoutInflater.inflate(
    resource: Int, 
    root: ViewGroup?, 
    attachToRoot: Boolean
): View!
// パラメータ
// resource: レイアウトファイル名(R値)
// root: インフレートしたビューを配置する親ビュー
// -> 通常はonCreateView()の仮引数containerを記述
// attachToRoot: インフレートしたビューをroot配下に配置するかどうか
// -> 通常はfalseを記述
```

### サンプルコード

```kotlin:MenuListFragment.kt
class MenuListFragment: Fragment() {
    // フラグメントのレイアウト(XML)のインフレート(フラグメントの生成)
    override fun onCreateView(
        inflater: LayoutInflater, 
        container: ViewGroup?, 
        savedInstanceState: Bundle?
    ): View? {
        // インフレートしたビュー
        val view = inflater.inflate(
            R.layout.<フラグメントのレイアウトファイル名>, 
            container,
            false
        )
        ...
        return view
    }
}
```

## アクティビティへの埋め込み
`fragment`タグを用いて`レイアウトファイル`(=`activity_main.xml`)に記述する。
埋め込む`フラグメント`は、`android:name`属性に`完全修飾名(com.~.<フラグメントクラス(=ファイル)名>)`を記述して指定する。

### サンプルコード

```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/fragmentMenuList"
        android:name="com.example.fragment.MenuListFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</FrameLayout>
```

### FrameLayout
[参考: 研修1日目](https://qiita.com/b150005/items/07475f27129a1a820fea)
`z`方向にビューを重ねて配置できる`レイアウト部品`。

***

# フラグメントでのオプションメニュー実装
[参考: 研修4日目](https://qiita.com/b150005/items/1f58b3418bb1690c2f4b)
`Fragment`クラスでの`onCreateOptionMenu()`、`onOptionsItemSelected()`メソッドの実装に加え、
`onCreate()`メソッドのブロック`{...}`内に`setHasOptionsMenu(true)`メソッドを記述する。

```kotlin:MenuListFragment.kt
// 発展:
class MenuListFragment: Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        setHasOptionsMenu(true)
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        super.onCreateOptionsMenu(menu, inflater)
        ...
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        ...
        return super.onOptionsItemSelected(item)
    }
}
```