[解決済み】フラグメントに空のコンストラクタは本当に必要なのか?
質問
私は
Fragment
で、複数の引数を取るコンストラクタがあります。私のアプリは、開発中は問題なく動作していましたが、実稼働環境では、ユーザーがこのクラッシュを経験することがあります。
android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment
make sure class name exists, is public, and has an empty constructor that is public
このエラーメッセージにあるように空のコンストラクタを作ることもできますが、そうすると
Fragment
.
なぜこのクラッシュがたまにしか起きないのか、不思議です。もしかしたら、私が使っている
ViewPager
が間違っているのでは?私はすべての
Fragment
の中にリストとして保存します。
Activity
. を使うことはありません。
FragmentManager
トランザクションは
ViewPager
私が見た例では、それを必要とせず、開発中はすべてうまくいっているように見えました。
どのように解決するのですか?
はい、そうです。
とにかく、コンストラクタをオーバーライドするべきではありません。そのためには
newInstance()
静的メソッドを定義し、引数でパラメータを渡します (バンドル)
例えば
public static final MyFragment newInstance(int title, String message) {
MyFragment f = new MyFragment();
Bundle bdl = new Bundle(2);
bdl.putInt(EXTRA_TITLE, title);
bdl.putString(EXTRA_MESSAGE, message);
f.setArguments(bdl);
return f;
}
もちろんこの方法でargsをつかむことも。
@Override
public void onCreate(Bundle savedInstanceState) {
title = getArguments().getInt(EXTRA_TITLE);
message = getArguments().getString(EXTRA_MESSAGE);
//...
//etc
//...
}
そして、フラグメントマネージャからこのようにインスタンスを作成します。
@Override
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState == null){
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.content, MyFragment.newInstance(
R.string.alert_title,
"Oh no, an error occurred!")
)
.commit();
}
}
この方法では、デタッチと再アタッチの場合、オブジェクトの状態は引数を通して保存することができます。Intentsに添付されたバンドルのようなものです。
理由 - 余分な読書
と疑問に思う人のために、理由を説明しようと思いました。
を見ることができます。
instantiate(..)
メソッドを
Fragment
クラスは
newInstance
メソッドを使用します。
public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) {
try {
Class<?> clazz = sClassMap.get(fname);
if (clazz == null) {
// Class not found in the cache, see if it's real, and try to add it
clazz = context.getClassLoader().loadClass(fname);
if (!Fragment.class.isAssignableFrom(clazz)) {
throw new InstantiationException("Trying to instantiate a class " + fname
+ " that is not a Fragment", new ClassCastException());
}
sClassMap.put(fname, clazz);
}
Fragment f = (Fragment) clazz.getConstructor().newInstance();
if (args != null) {
args.setClassLoader(f.getClass().getClassLoader());
f.setArguments(args);
}
return f;
} catch (ClassNotFoundException e) {
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": make sure class name exists, is public, and has an"
+ " empty constructor that is public", e);
} catch (java.lang.InstantiationException e) {
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": make sure class name exists, is public, and has an"
+ " empty constructor that is public", e);
} catch (IllegalAccessException e) {
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": make sure class name exists, is public, and has an"
+ " empty constructor that is public", e);
} catch (NoSuchMethodException e) {
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": could not find Fragment constructor", e);
} catch (InvocationTargetException e) {
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": calling Fragment constructor caused an exception", e);
}
}
http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#newInstance()
インスタンス化の際に、アクセッサが
public
と、そのクラスローダーがアクセスを許可していることを示します。
全体としてかなり厄介なメソッドですが、これによって
FragmentManger
を殺し、再作成する。
Fragments
をステートとする。(Androidサブシステムは同様のことを
Activities
).
クラス例
の呼び出しについてよく質問されます。
newInstance
. クラスメソッドと混同しないでください。 このクラス全体の例では、その使い方を示しています。
/**
* Created by chris on 21/11/2013
*/
public class StationInfoAccessibilityFragment extends BaseFragment implements JourneyProviderListener {
public static final StationInfoAccessibilityFragment newInstance(String crsCode) {
StationInfoAccessibilityFragment fragment = new StationInfoAccessibilityFragment();
final Bundle args = new Bundle(1);
args.putString(EXTRA_CRS_CODE, crsCode);
fragment.setArguments(args);
return fragment;
}
// Views
LinearLayout mLinearLayout;
/**
* Layout Inflater
*/
private LayoutInflater mInflater;
/**
* Station Crs Code
*/
private String mCrsCode;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCrsCode = getArguments().getString(EXTRA_CRS_CODE);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mInflater = inflater;
return inflater.inflate(R.layout.fragment_station_accessibility, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mLinearLayout = (LinearLayout)view.findViewBy(R.id.station_info_accessibility_linear);
//Do stuff
}
@Override
public void onResume() {
super.onResume();
getActivity().getSupportActionBar().setTitle(R.string.station_info_access_mobility_title);
}
// Other methods etc...
}
関連
-
[解決済み】Android - SDKバージョン23のアップデート後、ACTION-VIEWインテントフィルタを持つアクティビティを少なくとも1つ追加する。
-
[解決済み] [Solved] Unsupported method: ベースコンフィグ.getApplicationIdSuffix()
-
[解決済み】"ビットマップが大きすぎてテクスチャにアップロードできない"
-
[解決済み】フラグメントMyFragmentがアクティビティにアタッチされない。
-
[解決済み】Couldn't load memtrack module Logcat Error
-
[解決済み] Android Studioで「URIが登録されていません」と報告されるのはなぜですか?[クローズド]
-
[解決済み] 起動アクティビティを特定できませんでした。デフォルトのアクティビティが見つかりませんでした
-
[解決済み] Androidのgravityとlayout_gravityの違いは何ですか?
-
[解決済み] なぜフラグメントなのか、そしてアクティビティの代わりにフラグメントを使用するのはどんなときか?
-
[解決済み] フラグメントのインスタンス状態をバックスタックに正しく保存する方法は?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】パッケージ名(Google Analytics)に一致するクライアントが見つからない - 複数のproductFlavorsとbuildTypes
-
[解決済み] シンボル 'context' を解決できない
-
[解決済み】コンテンツには、id属性が「android.R.id.list」であるListViewが必要です。
-
[解決済み】Dalvikとdalvik-cacheとは何ですか?
-
[解決済み】起動アクティビティを特定できませんでした。デフォルトのアクティビティが見つかりませんでした
-
[解決済み] [Solved] java.lang.RuntimeException: アクティビティーのインスタンス化ができません ComponentInfo
-
[解決済み】getCheckedRadioButtonId()が無駄なintを返す?
-
[解決済み] Looper.prepare()を呼び出していないスレッドではハンドラを作成できない
-
[解決済み] setBackgroundDrawable() 非推奨
-
[解決済み] フラグメントで非デフォルトのコンストラクタを避けたい理由は?