ActivityとFragmentのライフサイクルを意識しなければならない状況で、
思っていたライフサイクルとは異なるフローで呼ばれていたため、
調査をしてみました。(主に破棄周り)
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
Fragmentのライフサイクル
http://developer.android.com/guide/components/fragments.html#Creating
ライフサイクル調査
さて、ここから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
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
を継承して各種コールバックのログを出力しているクラスです。
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
を継承して各種コールバックのログを出力しているクラスです。
// ここから起動処理
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
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
を継承して各種コールバックのログを出力しているクラスです。
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
を継承して各種コールバックのログを出力しているクラスです。
// ここから起動処理
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
今回は 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