ActivityとFragmentのライフサイクルと罠

ActivityとFragmentのライフサイクルを意識しなければならない状況で、
思っていたライフサイクルとは異なるフローで呼ばれていたため、
調査をしてみました。(主に破棄周り)

http://developer.android.com/guide/components/fragments.html 
> The lifecycle of the activity in which the fragment lives directly affects the lifecycle of the fragment, such that each lifecycle callback for the activity results in a similar callback for each fragment. For example, when the activity receives onPause(), each fragment in the activity receives onPause().

上記を読んで、
Activityが `onPause()` を受け取ったときに Fragmentも `onPause()` を受け取る。となっていますが、
ActivityよりもFragmentのほうが短命のはずなので、
破棄時は `Fragment.onDestroy()` の後に `Activity.onDestroy()` となると思っていました。
※逆に起動時は `Activity.onCreate()` の後に `Fragment.onCreate()` となると思っていました。

# 前置き

まずは、公式リファレンスのライフサイクルのおさらい。
(画像を貼るだけ)

## Activityのライフサイクル

http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle
![activity_lifecycle.png](https://qiita-image-store.s3.amazonaws.com/0/53393/7264706d-ccd7-b57a-3eca-cdf4c6675a3d.png)

## Fragmentのライフサイクル

http://developer.android.com/guide/components/fragments.html#Creating
![fragment_lifecycle.png](https://qiita-image-store.s3.amazonaws.com/0/53393/a23fa119-b41b-f7a2-b940-5ca1a79157e4.png)

# ライフサイクル調査

さて、ここからActivityとFragmentを使ったライフサイクルを調査していきます。
冒頭に記載した通り、主に破棄周りについて。

**環境**

* Android Studio: 1.3
* Mininum SDK: API 15 Android 4.0.3

**予想**

* `Fragment.onDestroyView()` -> `Fragment.onDestroy()` -> `Fragment.onDetach()` -> `Activity.onDestroy()`

**調査方法**

* Activityの起動から終了までのコールバックを追います。

**調査対象は2種類**

* `android.app.Activity` を継承したActivityに `android.app.Fragment` を追加する
    * 便宜上 `AppActivity` , `AppFragment` とします。
* `android.support.v4.app.FragmentActivity` を継承したActivityに `android.support.v4.app.Fragment` を追加する
    * 便宜上 `V4AppActivity` , `V4AppFragment` とします。

## ActivityとFragment

```java:AppActivityjava
public class AppActivity extends LifeCycleActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_app);

        if (savedInstanceState == null) {
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.add(R.id.container, new AppFragment());
            ft.commit();
        }
    }
}
```

※基底クラスの `LifeCycleActivity` は `Activity` を継承して各種コールバックのログを出力しているクラスです。

```java:AppFragment.java
public class AppFragment extends LifeCycleFragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        return inflater.inflate(R.layout.fragment_app, container, false);
    }
}
```

※基底クラスの `LifeCycleFragment` は `android.app.Fragment` を継承して各種コールバックのログを出力しているクラスです。

```:logcat
// ここから起動処理
D/LifeCycleActivity( 3575): onCreate
D/LifeCycleFragment( 3575): onAttach
D/LifeCycleFragment( 3575): onCreate
D/LifeCycleFragment( 3575): onCreateView
D/LifeCycleFragment( 3575): onActivityCreated
D/LifeCycleActivity( 3575): onStart
D/LifeCycleFragment( 3575): onStart
D/LifeCycleActivity( 3575): onResume
D/LifeCycleFragment( 3575): onResume
// ここから終了処理
D/LifeCycleFragment( 3575): onPause
D/LifeCycleActivity( 3575): onPause
D/LifeCycleFragment( 3575): onStop
D/LifeCycleActivity( 3575): onStop
D/LifeCycleFragment( 3575): onDestroyView
D/LifeCycleFragment( 3575): onDestroy
D/LifeCycleFragment( 3575): onDetach
D/LifeCycleActivity( 3575): onDestroy
```

※ログはActivityの起動から終了までです。

予想通り、
起動処理は `Activity` -> `Fragment` の順
終了処理は `Fragment` -> `Activity` の順

## FragmentActivityとFragment

```java:V4AppActivity
public class V4AppActivity extends LifeCycleFragmentActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_v4_app);

        if (savedInstanceState == null) {
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.add(R.id.container, new V4AppFragment());
            ft.commit();
        }
    }
}
```

* 前者との違い
    * 継承元が異なる( `extends Activity` が `extends FragmentActivity` に変わっている )
    * `getFragmentManager()` が `getSupportFragmentManager()` に変わっている

※基底クラスの `LifeCycleFragmentActivity ` は `FragmentActivity` を継承して各種コールバックのログを出力しているクラスです。

```java:V4AppFragment
public class V4AppFragment extends LifeCycleV4Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        return inflater.inflate(R.layout.fragment_v4_app, container, false);
    }
}
```

* 前者との違い
    * 継承元が異なる( `extends android.app.Fragment` が `extends android.support.v4.app.Fragment` に変わっている )

※基底クラスの `LifeCycleV4Fragment ` は `android.support.v4.app.Fragment` を継承して各種コールバックのログを出力しているクラスです。

```:logcat
// ここから起動処理
D/LifeCycleFragmentActivity( 3575): onCreate
D/LifeCycleFragmentActivity( 3575): onStart
D/LifeCycleV4Fragment( 3575): onAttach
D/LifeCycleV4Fragment( 3575): onCreate
D/LifeCycleV4Fragment( 3575): onCreateView
D/LifeCycleV4Fragment( 3575): onActivityCreated
D/LifeCycleV4Fragment( 3575): onStart
D/LifeCycleFragmentActivity( 3575): onResume
D/LifeCycleV4Fragment( 3575): onResume
// ここから終了処理
D/LifeCycleFragmentActivity( 3575): onPause
D/LifeCycleV4Fragment( 3575): onPause
D/LifeCycleFragmentActivity( 3575): onStop
D/LifeCycleV4Fragment( 3575): onStop
D/LifeCycleFragmentActivity( 3575): onDestroy
D/LifeCycleV4Fragment( 3575): onDestroyView
D/LifeCycleV4Fragment( 3575): onDestroy
D/LifeCycleV4Fragment( 3575): onDetach
```

※ログはActivityの起動から終了までです。

ここが予想外でした！
起動処理も終了処理も `Activity` -> `Fragment` の順

# Activityの状態とFragmentのライフサイクル

色々なサイトを巡ってライフサイクルを確認しましたが、
下記に記載した参考サイトでもライフサイクルがマチマチだし、

以下のデベロッパーサイトの図を見ても、
Activityのステートが `Destroyed` の時に、Fragmentの `onDestroyView()` , `onDestroy` , `onDetach()` となっているので、Activityの `onDestroy()` が来るタイミングは「Fragmentより前！」とか「Fragmentより後！」とかは無いのかなぁ。

今のところ Activity を使った場合のログの出力のされ方は毎回一定だし、
FragmentActivity を使った場合のログの出力のされ方も毎回一定で、
タイミングによって変化してるようには見えない。

http://developer.android.com/guide/components/fragments.html#Lifecycle
![activity_fragment_lifecycle.png](https://qiita-image-store.s3.amazonaws.com/0/53393/7a1ba6dd-13d2-8491-08bb-56da5d621235.png)

今回は `API 15: Android 4.0.3 IceCreamSandwich` でプロジェクトを作成したからFragmentActivityが継承されたMainActivityが出来たのだと思われる。
`API 22: Android 5.1 Lollipop` では、どうやらデフォルトでActivityが継承されるらしい。
きっと `Android 6.0 Marshmallow(マシュマロ)` でもActivityが継承されたものがデフォルトで作成される。

~~(実は `API 22(Lillipop)` や `API 23(Marshmallow)` では、今回調査対象とした2種類両方とも同じコールバックだったりして...)~~
調べてみると、 `API 22(Lillipop)` や `API 23(Marshmallow)` では、
デフォルトでは `appcompat-v7` とか `support-v4` は、使われていませんでした。
但し、自分でライブラリを追加して使うことができるので、試してみたところ上記調査結果通りのログになりました。

どちらにしても使い方に気を付けなければ！！

# 最後に

今回の調査で作ったサンプルアプリです。
https://github.com/chibi929/AndroidLifeCycle

# 参考サイト

http://techbooster.org/android/environment/17001/
http://qiita.com/suzukihr/items/90a93e79dc67c585de75
http://yuki312.blogspot.jp/2012/02/androidfragmentactivity.html