API呼び出し中にこのエラーが発生することはほとんどありません。
Java.lang.IllegalStateException: Fragment not attached to Activity
フラグメントが現在アクティビティに追加されているかどうかをチェックするためにisAdded()
メソッド内にコードを入れてみましたが、それでもこのエラーが発生することはほとんどありません。私はまだこのエラーを受けている理由を理解できません。どうすればそれを防ぐことができますか?
その行にその表示エラー
cameraInfo.setId(getResources().getString(R.string.camera_id));
下記は私が作っているサンプルのapi呼び出しです。
SAPI.getInfo(getActivity(),
new APIResponseListener() {
@Override
public void onResponse(Object response) {
cameraInfo = new SInfo();
if(isAdded()) {
cameraInfo.setId(getResources().getString(R.string.camera_id));
cameraInfo.setName(getResources().getString(R.string.camera_name));
cameraInfo.setColor(getResources().getString(R.string.camera_color));
cameraInfo.setEnabled(true);
}
}
@Override
public void onError(VolleyError error) {
mProgressDialog.setVisibility(View.GONE);
if (error instanceof NoConnectionError) {
String errormsg = getResources().getString(R.string.no_internet_error_msg);
Toast.makeText(getActivity(), errormsg, Toast.LENGTH_LONG).show();
}
}
});
このエラーは、次の2つの要因が組み合わさって発生します。
Activity
name__がまだフォアグラウンドにあるかどうかを知らずに、onResponse()
またはonError()
(メインスレッドで動作)のいずれかを呼び出します。 Activity
name__がなくなった(ユーザーが他の場所に移動した)場合、getActivity()
はnullを返します。Response
name__は匿名の内部クラスとして表現され、これは外部のActivity
name__クラスへの強い参照を暗黙的に保持しています。これは古典的なメモリリークを引き起こします。この問題を解決するために、あなたはいつもするべきです:
Activity activity = getActivity();
if(activity != null){
// etc ...
}
また、isAdded()
メソッドでもonError()
を使用します。
@Override
public void onError(VolleyError error) {
Activity activity = getActivity();
if(activity != null && isAdded())
mProgressDialog.setVisibility(View.GONE);
if (error instanceof NoConnectionError) {
String errormsg = getResources().getString(R.string.no_internet_error_msg);
Toast.makeText(activity, errormsg, Toast.LENGTH_LONG).show();
}
}
}
フラグメントのライフサイクルは非常に複雑でバグがいっぱいです。追加してみてください。
Activity activity = getActivity();
if (isAdded() && activity != null) {
...
}
私は非常に単純な解決策を見つけました isAdded() この現在のフラグメントがアクティビティに関連付けられているかどうかを識別するためのフラグメントメソッドの1つです。
これをフラグメントクラスのどこでも同じように使用できます。
if(isAdded())
{
// using this method, we can do whatever we want which will prevent **Java.lang.IllegalStateException: Fragment not attached to Activity** exception.
}
例外: Java.lang.IllegalStateException:フラグメント
DeadlineListFragment {ad2ef970}はActivityに添付されていません
カテゴリ:ライフサイクル
説明:バックグラウンドスレッドで時間のかかる操作(AsyncTaskなど)を実行すると、その間に新しいフラグメントが作成され、バックグラウンドスレッドが終了する前にアクティビティにデタッチされました。 UIスレッド内のコード(例えば、onPostExecute)はデタッチされたフラグメントを呼び出し、そのような例外を投げる。
解決策を修正します。
フラグメントを一時停止または停止するときにバックグラウンドスレッドをキャンセルする
フラグメントが添付されているかどうかを確認してからアクティビティからgetResources()を呼び出すには、isAdded()を使用します。
私は遅れるかもしれませんが誰かを助けるかもしれません.....これのための最善の解決策はグローバルなアプリケーションクラスインスタンスを作成してあなたのアクティビティが接続されていない特定のフラグメントでそれを呼び出すことです
以下のように
icon = MyApplication.getInstance().getString(R.string.weather_thunder);
これがアプリケーションクラスです
public class MyApplication extends Application {
private static MyApplication mInstance;
private RequestQueue mRequestQueue;
@Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
public static synchronized MyApplication getInstance() {
return mInstance;
}
}
このエラーは、どうしてもインスタンス化できないフラグメントをインスタンス化している場合に発生する可能性があります。
Fragment myFragment = MyFragment.NewInstance();
public classs MyFragment extends Fragment {
public void onCreate() {
// Some error here, or anywhere inside the class is preventing it from being instantiated
}
}
私の場合、使用しようとしたときにこれに出会いました。
private String loading = getString(R.string.loading);
フラグメントではisAdded()
を使用しますフラグメントが現在Activityにアタッチされている場合はtrueを返します。
アクティビティ内をチェックしたい場合
Fragment fragment = new MyFragment();
if(fragment.getActivity()!=null)
{ // your code here}
else{
//do something
}
誰かに役立つことを願っています
この問題に対処するために、私は以下のアプローチを採用しました。このようなアクティビティメソッドのラッパーとして機能する新しいクラスを作成しました
public class ContextWrapper {
public static String getString(Activity activity, int resourceId, String defaultValue) {
if (activity != null) {
return activity.getString(resourceId);
} else {
return defaultValue;
}
}
//similar methods like getDrawable(), getResources() etc
}
メソッドを直接呼び出すのではなく、フラグメントまたはアクティビティからリソースにアクセスする必要がある場合は、このクラスを使用します。アクティビティcontext
がnull
でない場合はアセットの値を返し、context
がnullの場合はデフォルト値を渡します(これは関数の呼び出し元によっても指定されます)。
重要これは解決策ではありません、これはあなたが優雅にこのクラッシュを処理することができる有効な方法です。アクティビティインスタンスをnullとして取得している場合は、ログを追加して、可能であればそれを修正しようとします。
この問題は、利用できないコンテキストを呼び出すとき、または呼び出すときにnullのときに発生します。これは、バックグラウンドスレッドでメインアクティビティスレッドのコンテキストを呼び出す場合、またはメインアクティビティスレッドでバックグラウンドスレッドのコンテキストを呼び出す場合の状況です。
たとえば、私は次のように共有設定文字列を更新しました。
editor.putString("penname",penNameEditeText.getText().toString());
editor.commit();
finish();
そしてその直後にfinish()と呼びました。これで、コミットがメインスレッドで実行され、終了するまで他のAsyncコミットが停止した場合は停止します。そのため、そのコンテキストは書き込みが完了するまで有効です。したがって、以前のコンテキストはライブであり、エラーが発生します。
そのため、このコンテキストの問題があるコードがある場合は、必ずコードを再確認してください。
時々、この例外はサポートライブラリの実装のバグによって引き起こされます。最近私はそれを取り除くために26.1.0から25.4.0にダウングレードしなければなりませんでした。
これは、フラグメントにコンテキストがない場合に発生します。したがって、getActivity()メソッドはnullを返します。取得する前にコンテキストを使用していないか、またはアクティビティがもう存在していないかどうかを確認してください。 fragment.onCreateでコンテキストを使用し、APIレスポンスの後で通常この問題を起こす