Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

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

Fragmentのライフサイクル

http://developer.android.com/guide/components/fragments.html#Creating
fragment_lifecycle.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

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();
        }
    }
}

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

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);
    }
}

※基底クラスの LifeCycleFragmentandroid.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

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 Activityextends FragmentActivity に変わっている )
    • getFragmentManager()getSupportFragmentManager() に変わっている

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

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.Fragmentextends android.support.v4.app.Fragment に変わっている )

※基底クラスの LifeCycleV4Fragmentandroid.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

今回は 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

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away