Fragmentをpublic以外のアクセス修飾子でクラス定義していると、FragmentManagerに追加する際、以下のIllegalStateExceptionが投げられクラッシュする。
Caused by: java.lang.IllegalStateException: Fragment com.sample.test.myapplication.MainActivity.MyDialogFragment must be a public static class to be properly recreated from instance state. at androidx.fragment.app.FragmentTransaction.doAddOp(FragmentTransaction.java:165) at androidx.fragment.app.BackStackRecord.doAddOp(BackStackRecord.java:179) at androidx.fragment.app.FragmentTransaction.add(FragmentTransaction.java:125) at androidx.fragment.app.DialogFragment.show(DialogFragment.java:154) at com.sample.test.myapplication.MainActivity.onClick(MainActivity.java:32)
このエラーが出たときの対処法は、
Fragmentを別のファイルに定義し、publicクラスにすればよい。
本記事では、何故このような制約があるのかについて書いていく。
Fragmentを別のファイルに定義し、publicクラスにすればよい。
本記事では、何故このような制約があるのかについて書いていく。
何故エラーは起こるのか
Androidのシステムは、スマホを横にして横表示に切り替えると、画面を横の比率に調整しつつ画面の内容を維持する仕組みがある。
ボタン押下でDialogFragmentを表示させ、
そのまま横にするとダイアログが維持されている図
このときアプリ内部では、縦画面のActivityを破棄し、横画面用のActivityへの作り直しが発生している。Activityが作り直されると当然Fragmentも破棄、再生成が行われる。
しかし、このときFragmentのコンストラクタがPublicではなかった場合、AndroidシステムはFragmentのインスタンスの生成ができず、この画面を復旧させる機能が実現できなくなる。
なので、
Fragmentの生成は、外部からでもできるようにpublicにしないといけない。
というルールが備わった。
実装ではどうなっているのか
このpublicのチェックはFragmentManagerに追加時に行われる。FragmentManagerに追加しない限りFragmentが再生成する必要がないわけなので、当然のタイミングだと思う。
実装内容はここ
/** FragmentTransaction.java */ void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) { final Class<?> fragmentClass = fragment.getClass(); final int modifiers = fragmentClass.getModifiers(); if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers) || (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) { throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName() + " must be a public static class to be properly recreated from" + " instance state."); }表示させるフラグメントのClassクラスを取得して以下をチェックしている
- 匿名クラスか? ⇒ 当然、匿名クラスなら外部からコンストラクタが実行できない
- Publicなクラス以外か? ⇒ Publicクラス以外は外部からコンストラクタが実行できない
- インナークラスの場合、Staticなクラスではないか? ⇒ たとえPublicクラスであっても、インナークラスの場合はstaticでないと、外部からコンストラクタは呼べない
このチェックに引っかかれば、IllegalStateExceptionが投げられる仕組みだ。
以上の理由から、
Fragmentはpublicクラスにすることで、このエラーを回避できる。
0 件のコメント:
コメントを投稿