Java

Fragmentのライフサイクル呼び出し順|Javaで押さえる13コールバックと落とし穴

Fragmentのライフサイクル呼び出し順|Javaで押さえる13コールバックと落とし穴

AndroidのFragmentは、onAttachからonDetachまで13個のコールバックを持ちます。12個は決まった順番で呼ばれ、onSaveInstanceStateだけがAPIレベルと状況によって位置を変えます。この順番を取り違えると、Viewがまだ無い段階でfindViewByIdを呼んでクラッシュしたり、破棄したはずのViewを参照し続けてメモリリークを起こしたりします。この記事では、androidx.fragment 1.9.0(2026年8月12日リリース)を前提に、生成時と破棄時の呼び出し順、onCreateViewとonViewCreatedの分担、onDestroyViewで何を消すべきかを、Javaのコードで具体的に示します。

まとめ:13コールバックの呼び出し順と実装分担3点

生成時はonAttachonCreateonCreateViewonViewCreatedonViewStateRestoredonStartonResumeの順で呼ばれます。破棄時はonPauseonStoponDestroyViewonDestroyonDetachで、onSaveInstanceStateだけはAPI 28を境にonStopとの前後が入れ替わり、さらにバックスタック上ではView破棄後に呼ばれることもあります。

実装で押さえるべき分担は3点です。onCreateViewはレイアウトのinflateだけを行い、findViewByIdやリスナー設定はonViewCreatedに置きます。LiveDataの購読はthisではなくgetViewLifecycleOwner()を渡します。onDestroyViewではViewバインディングをnullに戻し、Fragment側にView参照を残しません。

そしてsetRetainInstanceonActivityCreatedなど、かつて定番だったAPIは現行のandroidx.fragmentでは非推奨です。置き換え先は本文の対照表にまとめました。以降で、呼び出し順の全体像から順に見ていきます。

ライフサイクル13コールバックの呼び出し順

Fragmentのコールバックは、生成方向(上向き)と破棄方向(下向き)で対称に並びます。公式のライフサイクルガイドは「onAttach() is always called before any Lifecycle state changes」「onDetach() is always called after any Lifecycle state changes」と明記しており、この2つが必ず両端に来ます。ここで数える13個は、実装で日常的にオーバーライドするものに限っています。非推奨のonActivityCreatedと、アニメーションやメニュー関連のonCreateAnimationonInflateなどは除いています。

コールバック 局面 この時点で書く処理
1 onAttach 生成 Contextの取得
2 onCreate 生成 Viewに依存しない初期化
3 onCreateView 生成 レイアウトのinflateのみ
4 onViewCreated 生成 View初期化・LiveData購読
5 onViewStateRestored 生成 View状態の復元後の処理
6 onStart 表示 子FragmentManagerの操作
7 onResume 表示 操作受付・再生の再開
8 onPause 離脱 操作受付・再生の停止
9 onStop 離脱 更新処理の停止
10 onSaveInstanceState 離脱 Bundleへの状態保存
11 onDestroyView 破棄 View参照の解放
12 onDestroy 破棄 Fragment全体の後始末
13 onDetach 破棄 Contextの切り離し

縦に並べると、Viewを扱える区間が3番から11番までに限られていることが見て取れます。

[生成]  onAttach
          ↓  onCreate
          ↓  onCreateView          ← inflate だけ
          ↓  onViewCreated         ← findViewById・購読開始
          ↓  onViewStateRestored   ← View状態はここで戻る
          ↓  onStart
          ↓  onResume
[表示中]
          ↓  onPause
          ↓  onStop
          ↓  onSaveInstanceState   ← API 28 以降の位置。27 以前は onStop の前
          ↓  onDestroyView         ← View 参照を null に戻す
          ↓  onDestroy
[破棄]  onDetach

生成時の呼び出し順とonViewStateRestoredの位置

検索でよく問われる「onCreateView、onAttach、onViewCreated、onStart、onCreateはどの順番か」の答えは、onAttachonCreateonCreateViewonViewCreatedonStartです。onCreateonCreateViewは隣り合っていますが、役割は別です。前者はViewが存在しない段階の初期化、後者はViewの生成そのものを担います。名前の近さと役割の遠さが取り違えの起点になります。

この2つの間に、忘れられがちなonViewStateRestoredが挟まります。公式ガイドは、Viewが生成された後に以前のView状態が復元されてからViewのLifecycleがCREATEDへ移り、この遷移がonViewStateRestoredを呼ぶと説明しています。つまりEditTextの入力内容やRecyclerViewのスクロール位置が戻るのはonViewCreatedの後です。onViewCreatedで入力欄を初期化すると、その後の復元で上書きされます。

onCreateが受け取るsavedInstanceStateには公式の注記があります。フラグメントが初めて生成されたときはnullですが、再生成のときはonSaveInstanceStateをオーバーライドしていなくても常に非nullです。nullチェックだけで「初回かどうか」を判定できるのはこのためです。

破棄時の呼び出し順とonSaveInstanceStateが動く2つの条件

破棄方向はonPauseonStoponDestroyViewonDestroyonDetachです。androidxのFragment.javaのjavadocも、onDestroyViewについて「called after onStop() and before onDestroy()」と明記しています。

位置が動くのはonSaveInstanceStateだけで、条件は2つあります。1つ目はAPIレベルです。公式ガイドは「For all API levels prior to API 28, onSaveInstanceState() is invoked before onStop(). For API levels 28 and higher, the calling order is reversed.」と述べています。API 27以前はonPauseonSaveInstanceStateonStop、API 28以降はonPauseonStoponSaveInstanceStateです。

2つ目はバックスタックです。Fragment.javaのjavadocは「this method may be called at any time before onDestroy(). There are many situations where a fragment may be mostly torn down (such as when placed on the back stack with no UI showing), but its state will not be saved until its owning activity actually needs to save its state.」と注意しています。バックスタックに積まれてUIを持たない、つまりonDestroyViewを済ませたFragmentに対しても、後からonSaveInstanceStateが呼ばれます。Viewがある前提で書いた保存処理はここで落ちるため、対処は後述のnullガードの項で示します。

なおonSaveInstanceStateは破棄のたびに呼ばれるわけではありません。バックスタックに積まずにremove()したときやホストのActivityがfinishするときは状態が保存されないため、ここに書いた保存処理は使われずに消えます。

呼び出し順を実機で確認するJavaコード

順番は暗記するより、実装中のプロジェクトで1回ログに出したほうが確実です。まず依存関係を追加します。テスト用のartifactは2つに分かれており、公式のテストガイドはfragment-testing-manifestdebugImplementationで、fragment-testingandroidTestImplementationで宣言するよう示しています。

dependencies {
    def fragment_version = "1.9.0"

    implementation "androidx.fragment:fragment:$fragment_version"
    debugImplementation "androidx.fragment:fragment-testing-manifest:$fragment_version"
    androidTestImplementation "androidx.fragment:fragment-testing:$fragment_version"
}

次に、13コールバックすべてにログを仕込んだFragmentを用意します。画面を回転させる、ホームに戻る、バックキーで戻るといった操作をしながらlogcatをFragmentLifecycleタグで絞ると、状況ごとにどこまで下がってどこから戻るかが読み取れます。

public class LifecycleLogFragment extends Fragment {

    // ログの番号は API 28 以降の順序。API 27 以前は 10 が 9 より先に出る
    private static final String TAG = "FragmentLifecycle";

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        Log.d(TAG, "1 onAttach");
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "2 onCreate saved=" + (savedInstanceState != null));
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater,
                             @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        Log.d(TAG, "3 onCreateView");
        return inflater.inflate(R.layout.fragment_sample, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        Log.d(TAG, "4 onViewCreated");
    }

    @Override
    public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
        super.onViewStateRestored(savedInstanceState);
        Log.d(TAG, "5 onViewStateRestored");
    }

    @Override
    public void onStart() {
        super.onStart();
        Log.d(TAG, "6 onStart");
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.d(TAG, "7 onResume");
    }

    @Override
    public void onPause() {
        super.onPause();
        Log.d(TAG, "8 onPause");
    }

    @Override
    public void onStop() {
        super.onStop();
        Log.d(TAG, "9 onStop");
    }

    @Override
    public void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG, "10 onSaveInstanceState");
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.d(TAG, "11 onDestroyView");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "12 onDestroy");
    }

    @Override
    public void onDetach() {
        super.onDetach();
        Log.d(TAG, "13 onDetach");
    }
}

FragmentScenarioによる呼び出し順の固定

ログでの確認は再現条件を人手で作るため、回帰の検知には向きません。fragment-testingが提供するFragmentScenarioを使うと、任意のライフサイクル状態への遷移と構成変更の再生成をテストコードから直接起こせます。公式ガイドが「run each of the API’s methods in your test’s instrumentation thread」と指定しているとおり、置き場所はapp/src/androidTest配下の計装テストです。

@RunWith(AndroidJUnit4.class)
public class ProfileFragmentTest {

    @Test
    public void restoresDraft_afterRecreate() {
        // FragmentScenario は Closeable なので try-with-resources で閉じる
        try (FragmentScenario<ProfileFragment> scenario =
                     FragmentScenario.launchInContainer(ProfileFragment.class)) {

            scenario.onFragment(fragment -> {
                EditText input = fragment.requireView().findViewById(R.id.draft_input);
                input.setText("下書き");
            });

            // CREATED まで落とすと onPause から onDestroyView まで実際に走る
            scenario.moveToState(Lifecycle.State.CREATED);
            scenario.moveToState(Lifecycle.State.RESUMED);
            scenario.recreate();

            scenario.onFragment(fragment -> {
                EditText input = fragment.requireView().findViewById(R.id.draft_input);
                assertEquals("下書き", input.getText().toString());
            });
        }
    }
}

moveToState(Lifecycle.State.CREATED)はViewの破棄までを、recreate()は画面回転と同じ再生成を再現します。構成変更とプロセス終了を人手で再現するのは手間がかかるため、復元を伴う画面にはこのテストを1本置く価値があります。

フラグメントとは|Activityとの役割分担

Fragmentは、Activityの中に埋め込んで使うUIの部品です。単体では画面として起動できず、FragmentManagerによって状態が管理されます。Activityとは別に自分自身のライフサイクルを持つため、持ち主より短命にも長命にもなります。この性質が、呼び出し順を難しくしている根本の理由です。

Activityはシステムから見た画面の単位で、マニフェストに登録され、インテントで起動されます。Fragmentはその内側に置く部品なので、1つのActivityに複数を同時に配置できます。タブレットで一覧と詳細を左右に並べ、スマートフォンでは1枚ずつ表示するといった出し分けは、この構造があって成立します。

公式ガイドには、Fragmentの状態はFragmentManagerの状態を超えられず、親より進んだ状態にもなれないという制約が示されています。親のActivityが開始される前に子のFragmentが開始されることはなく、逆に子は親より先に停止します。加えて、レイアウトXMLでFragmentを配置する<fragment>タグには「FragmentManagerの状態を超えて進んでしまう」という注意が付いており、FragmentContainerViewを使うよう案内されています。なお実装対象のクラスはandroidx.fragment.app.Fragmentで、OS標準のandroid.app.Fragmentは非推奨です。詳細は後半の対照表で扱います。

実装言語をこれから決める場合は、Androidアプリ開発の言語はKotlinとJavaのどちらか?選定基準と環境まで解説で選定基準を整理しています。

onCreateViewとonViewCreatedの使い分け

旧来のサンプルには、onCreateViewの中でinflateしたViewに対してfindViewByIdを呼び、そのままリスナーを設定するコードが多く残っています。androidxのFragment.javaのjavadocは、この書き方を明確に否定しています。「It is recommended to only inflate the layout in this method and move logic that operates on the returned View to onViewCreated()」、つまりこのメソッドではレイアウトのinflateだけを行い、返したViewを操作するロジックはonViewCreatedへ移せ、という指示です。

対するonViewCreatedについて、公式ガイドは「Viewの初期状態の設定、Viewを更新するLiveDataの購読開始、RecyclerViewやViewPager2のアダプタ設定に適した場所」と説明しています。役割の線引きははっきりしていて、Viewを作るのがonCreateView、作られたViewを触るのがonViewCreatedです。

private OrderViewModel viewModel;  // onCreate で ViewModelProvider から取得しておく

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
                         @Nullable ViewGroup container,
                         @Nullable Bundle savedInstanceState) {
    // inflate だけを行う。findViewById やリスナー設定は書かない
    return inflater.inflate(R.layout.fragment_order, container, false);
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    RecyclerView list = view.findViewById(R.id.order_list);
    OrderAdapter adapter = new OrderAdapter();  // ListAdapter を継承した実装
    list.setAdapter(adapter);

    // 購読の LifecycleOwner は this ではなく getViewLifecycleOwner()
    viewModel.getOrders().observe(getViewLifecycleOwner(), adapter::submitList);
}

この分離には実務上の効き目があります。onCreateViewにView操作を書くと、Viewが再生成されるたびに走る処理と一度きりでよい処理が同じメソッドに同居し、バックスタックから戻ったときの二重初期化を追いにくくなります。

Viewライフサイクルの独立とonDestroyViewでの参照解放

FragmentのViewは、Fragment本体とは別のLifecycleを持ちます。Fragment.javaのjavadocは「in cases of detached Fragments, the lifecycle of the Fragment can be considerably longer than the lifecycle of the View itself」と述べています。Fragmentは生きているのにViewだけが死んでいる期間が存在する、という点がonDestroyView関連のバグの原因です。

Viewライフサイクルのイベント発火順

getViewLifecycleOwner()のjavadocは、ViewのLifecycleイベントが発火する位置をコールバック基準で列挙しています。ON_CREATEはonViewStateRestoredの後、ON_STARTはonStartの後、ON_RESUMEはonResumeの後です。下向きは反転し、ON_PAUSEはonPauseの前、ON_STOPはonStopの前、ON_DESTROYはonDestroyViewの前に発火します。

ViewのLifecycleが有効なのはonDestroyViewの呼び出しまでです。javadocは、その後はgetView()がnullを返し、ViewのLifecycleは破棄され、getViewLifecycleOwner()はIllegalStateExceptionを投げると明記しています。非同期処理の完了コールバックの中でこのメソッドを呼ぶ設計は、遅れて戻ってきた瞬間に落ちます。

ViewBindingのnull化とLiveData購読の指定先

Viewが先に死ぬという性質から、実装の鉄則が2つ導かれます。1つはバインディングの解放です。公式ガイドはonDestroyViewの時点で「all references to the fragment’s view should be removed」と述べています。Fragmentのフィールドにバインディングを持たせたままにすると、破棄済みのView階層がFragmentの寿命の間ずっと残ります。

private FragmentOrderBinding binding;

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
                         @Nullable ViewGroup container,
                         @Nullable Bundle savedInstanceState) {
    binding = FragmentOrderBinding.inflate(inflater, container, false);
    return binding.getRoot();
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    // View より長生きする Fragment に参照を残さない
    binding = null;
}

もう1つがLiveDataの購読先です。observe()の第1引数にthisを渡すとFragment本体の寿命に紐づくため、Viewが作り直されるたびに購読が積み重なります。すると1回の更新で、積み重なった回数だけコールバックが走ります。getViewLifecycleOwner()を渡せば、ON_DESTROYの時点で購読が自動的に解除されます。バックスタックを使う画面でリストが二重に描画される症状は、この取り違えで再現します。

状態保存の使い分け|onSaveInstanceState・ViewModel・バックスタック

「入力内容が消える」という不具合は、どの状態がどの操作で消えるかを把握していないことが原因です。公式の状態保存ガイドは、操作と状態の種類の組み合わせを表で示しています。VariablesはFragmentが持つ変数(原文は local variables in the fragment)、View Stateは各Viewが持つ値、SavedStateはonSaveInstanceStateで保存する値、NonConfigはサーバーなど外部から取得したデータを指します。

操作別に生き残る状態の対応表

操作 変数 View状態 SavedState NonConfig
バックスタックへの追加 残る 残る 消える 残る
構成変更 消える 残る 残る 残る
プロセス終了と再生成 消える 残る 残る 条件付き
バックスタックなしのremove 消える 消える 消える 消える
ホストのfinish 消える 消える 消える 消える

プロセス終了時のNonConfigは、ViewModel向けのSaved Stateモジュールを使う場合に限って残ります。表から読み取るべきは、バックスタックへの追加では変数が生き残る一方、構成変更では消えるという非対称です。バックスタックではFragmentのインスタンス自体が保持されるためonCreateは再実行されませんが、画面回転ではインスタンスが作り直されるため、フィールドに置いた値はonSaveInstanceStateを通さない限り失われます。

onSaveInstanceStateでViewを読むときのnullガード

ここで先ほどのbinding = nullonSaveInstanceStateが衝突します。バックスタック上のFragmentに対してonSaveInstanceStateが呼ばれる時点で、bindingは既にnullです。保存処理をView経由で書くと、その瞬間にNullPointerExceptionで落ちます。Viewがある間に値をフィールドへ退避し、保存時はフィールドを使うのが安全な形です。

private static final String KEY_DRAFT = "draft_text";
private String draft = "";

@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    // View がある間は View から、無い場合は退避済みの値から保存する
    if (binding != null) {
        draft = binding.draftInput.getText().toString();
    }
    outState.putString(KEY_DRAFT, draft);
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    draft = binding.draftInput.getText().toString();  // View がある最後の機会に退避
    binding = null;
}

@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
    super.onViewStateRestored(savedInstanceState);
    if (savedInstanceState != null) {
        draft = savedInstanceState.getString(KEY_DRAFT, "");
        binding.draftInput.setText(draft);
    }
}

退避先のフィールドを増やしたくない場合は、値の置き場をViewModelのSavedStateHandleへ寄せる方法もあります。その場合はFragmentのコールバックから状態保存の責務自体が消えるため、上のガードも不要になります。

setRetainInstanceの非推奨とViewModelへの置き換え

構成変更をまたいでデータを保持する目的でsetRetainInstance(true)を使う解説は、いまも数多く出回っています。androidxのFragment.javaでこのメソッドは非推奨で、javadocの指示は「Fragment自体を保持するのではなく、非保持のFragmentを使い、保持したい状態はそのFragmentに紐づくViewModelに置け」というものです。ViewModelのコンストラクタとonCleared()が、保持する状態の生成と最終破棄の合図になるとも書かれています。

public class OrderViewModel extends ViewModel {

    private final MutableLiveData<List<Order>> orders = new MutableLiveData<>();

    public LiveData<List<Order>> getOrders() {
        return orders;
    }

    @Override
    protected void onCleared() {
        // 画面が完全に終了したときだけ呼ばれる。購読やジョブの停止はここ
    }
}

// Fragment 側(onCreate で取得してよい)
viewModel = new ViewModelProvider(this).get(OrderViewModel.class);

ViewModelへ寄せる利点は、破棄のタイミングが1か所に集約されることです。setRetainInstanceではFragment自身が生き残るため、Viewの破棄とデータの破棄が同じクラスに混在し、どちらの寿命の話をしているのかコードから読み取れなくなります。バックグラウンドで走らせたい処理そのものは、WorkManagerとは?Androidの遅延実行の仕組みと採用判断を解説で扱う仕組みに預けるほうが確実です。

呼び出し順に起因する典型障害と対処

ここまでの仕様から機械的に導ける不具合を2つ挙げます。どちらも呼び出し順の理解だけで回避できます。

バックスタック復帰でonCreateが呼ばれない理由

公式ガイドは、バックスタックの最上位に積まれたFragmentがCREATEDからSTARTED、RESUMEDへと上がり、逆にバックスタックから取り出されるときはRESUMEDからSTARTED、CREATEDへ下がると説明しています。下限がCREATEDである以上、戻ってきたときの出発点もCREATEDで、onCreateは再実行されません。実際に走るのはonCreateView以降です。

onCreateにAPI呼び出しを書いた画面が、戻ったときだけデータを取り直さないのはこのためです。Viewが作り直されるたびに実行してよい処理はonViewCreatedに置いてください。

IllegalStateExceptionが出る2つの条件

ViewのLifecycleに関するIllegalStateExceptionには、発生条件が2つあります。1つはonDestroyViewより後にgetViewLifecycleOwner()を呼んだ場合です。もう1つは、onCreateViewの中でViewのLifecycleへアクセスしながら非nullのViewを返さなかった場合で、javadocが明示的に警告しています。非同期の完了コールバックからViewを触る設計をやめ、ViewModelのLiveDataを経由してUIを更新すれば、どちらも構造的に起こりません。コルーチンでスコープを揃える方法はKotlin Coroutinesとは?suspendの仕組みと構造化並行性・採用判断で整理しています。

非推奨APIと移行先の対照表

Fragmentの周辺APIは置き換えが続いており、古い解説をそのまま写すと非推奨のAPIに当たります。代替はいずれもFragment.javaの@deprecatedjavadocに書かれた指示に対応します。

非推奨API 代替
android.app.Fragment androidx.fragment.app.Fragment
onActivityCreated() onViewCreated() と onCreate()
setRetainInstance(true) ViewModel
setTargetFragment() setFragmentResultListener()
setUserVisibleHint() setMaxLifecycle()
setHasOptionsMenu() MenuProvider
<fragment>タグでの配置 FragmentContainerView

1行目はライブラリの選択そのものです。APIリファレンスはandroid.app.Fragmentを「Added in API level 11 / Deprecated in API level 28」と表示しており、現在の実装対象はJetpackのandroidx.fragment.app.Fragmentだけです。古いサンプルを写すときは、importがandroid.appで始まっていないかを最初に確認してください。

onActivityCreatedはViewを触るコードをonViewCreatedへ、それ以外の初期化をonCreateへ分けるよう案内されています。setTargetFragmentは、要求側がsetFragmentResultListener()でリクエストキーを登録し、結果を返す側が同じキーでsetFragmentResult()を呼ぶ形に変わりました。javadocが指すのはFragmentManagerのメソッドなので、JavaではgetParentFragmentManager()から呼びます。

androidx.fragmentの最新安定版は1.9.0で、Google Mavenのメタデータ上の更新は2026年8月12日です。バージョンは短い周期で上がるため、採用時はGoogle Mavenの値を確認してください。同じ1.9.0ではfragment-composeも配信されており、既存のFragmentを器として残したままUIをComposeへ移す経路が用意されています。

この対照表の長さ自体が判断材料になります。2026年の新規画面をFragmentの積み上げで設計する理由は薄いというのが筆者の見解です。まず新規画面をComposeで作り、既存画面は不具合対応のついでに移すのが現実的です。ただしfragment-composeの公開APIはComposable関数とKotlin拡張関数で構成されており、Javaからは呼べません。Java資産の画面を移すならKotlin化が前提になるため、着手前に言語選定の判断を済ませておく必要があります。移行先の全体像はJetpack Composeとは?宣言的UIの仕組みとBOM運用・採用判断を解説にまとめています。

一方で、Fragmentを今すぐ捨てるべきとまでは言えません。Navigationコンポーネントの画面遷移はFragmentを目的地として扱う構成が現役で、ダイアログやマルチペインを含む既存画面の全面移行は工数に見合わないことが多いためです。判断の分かれ目は移行の工数ではなく、その画面をこの先も触り続けるかどうかです。

よくある質問

onCreateView、onAttach、onViewCreated、onStart、onCreateはどの順番で呼ばれますか?

onAttach、onCreate、onCreateView、onViewCreated、onStartの順です。onCreateはView生成前の初期化、onCreateViewはView生成そのものと役割が分かれており、名前が似ているだけで担当が違います。onCreateViewとonViewCreatedは連続して呼ばれ、その後onStartとの間にonViewStateRestoredが挟まります。

onDestroyViewとonDestroyの違いは何ですか?

onDestroyViewはFragmentのViewだけが破棄されるときに呼ばれ、Fragmentのインスタンスは残ります。onDestroyはFragment自体が破棄されるときに呼ばれます。javadocはonDestroyViewをonStopの後、onDestroyの前と定めています。バックスタックに積んで別のFragmentへ置き換えたときはonDestroyViewまでしか進まないため、View参照の解放はonDestroyではなくonDestroyViewに書く必要があります。

フラグメントとは何ですか?

Activityの中に埋め込んで使うUIの部品で、Activityとは別に自分自身のライフサイクルを持ちます。1つのActivityに複数配置でき、画面サイズに応じた出し分けや部分的な差し替えができます。単体では画面として起動できず、FragmentManagerによって状態が管理されます。現在の実装対象はandroidx.fragment.app.Fragmentで、OS標準のandroid.app.FragmentはAPI 28で非推奨になっています。

onSaveInstanceStateはいつ呼ばれますか?

状態が保存される場面、つまり画面回転などの構成変更やプロセス終了の前に呼ばれます。onStopとの前後関係はAPIレベルで異なり、API 27以前はonStopの前、API 28以降はonStopの後です。加えてjavadocは「onDestroy()より前ならいつでも呼ばれ得る」と注意しており、バックスタックに積まれてViewを破棄済みのFragmentにも呼ばれます。逆に、バックスタックに積まずにremove()した場合やホストのActivityがfinishする場合は状態が保存されません。

setRetainInstanceの代わりに何を使えばよいですか?

ViewModelです。androidxのFragment.javaのjavadocは、Fragment自体を保持するのではなく非保持のFragmentを使い、保持したい状態はそのFragmentに紐づくViewModelへ置くよう指示しています。ViewModelのコンストラクタが状態の生成、onCleared()が最終破棄の合図になります。プロセス終了もまたいで復元したい値は、ViewModel向けのSaved Stateモジュールを併用してください。

関連記事

資料請求

RELATED POSTS 関連記事