Edited at

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