java.lang.IllegalStateException:アクティビティにフラグメントがアタッチされていません


148

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();
                        }
                    }
                });

cameraInfo.setId(getActivity()。getResources()。getString(R.string.camera_id));
Ashwin H

回答:


203

このエラーは、次の2つの要因が組み合わさったために発生します。

  • HTTP要求は、完了すると、がまだフォアグラウンドにあるかどうかを認識せずに、onResponse()またはonError()(メインスレッドで機能する)のいずれかを呼び出しますActivity。場合Activity(ユーザーが別の場所にナビゲート)なくなって、getActivity()ヌルを返します。
  • ボレーResponseは匿名の内部クラスとして表現され、暗黙的に外部Activityクラスへの強い参照を保持します。これにより、古典的なメモリリークが発生します。

この問題を解決するには、常に次のことを行う必要があります。

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();
        }
    }
}

2
AsyncTask内からVolleyリクエストとを使用する場合Activity、NPEを回避するための確実な方法はありません。Activityスレッドの1つがバックグラウンドで何かを実行しているときに、ユーザーが現在から離れてナビゲートする可能性は常にあり、スレッドが完了onPostExecute()またはonResponse()呼び出されたときに、はありませんActivity。あなたができることは、コードのさまざまなポイントでnull参照をチェックすることだけです。これは完全なものではありません:)
YS

2
Androidモンキーテスト(adb shell monkey)は、このエラーを一般的またはグローバルな方法で説明していない場合、このエラーを根絶するのに非常に適しています。
Groovee60 2016

5
isAdded()で十分です。最終的なパブリックブールisAdded(){mActivityを返す!= null && mAdded; }
lannyf

2
@ruselli:addedブールフラグと現在のActivityインスタンスがそうであるかどうかをチェックしますnull
YS

1
@gauravjainフラグメントから非同期リクエスト(HTTP呼び出しなど)を直接行わないようにします。アクティビティから実行してください。問題はありません。また、FragmentManagerからFragment参照をクリアします。これは良い方法であり、メモリリークを回避するための最良の方法です。
YS

56

フラグメントのライフサイクルは非常に複雑でバグが多いため、以下を追加してみてください:

Activity activity = getActivity(); 
if (isAdded() && activity != null) {
...
}

2
どこに置けばいいの?
VaclovasRekašiusJr. 2017

1
@VaclovasRekašiusJr。フラグメント内からアクティビティにアクセスしたい場所のほとんどのようです。楽しい!
TylerJames、2018年

2
activity == nullの場合はどうすればよいですか?生きている私のアプリケーション@Miroslav保つために
パベル

isAdded()を見ると、「activity!= null」は冗長ではないことがわかります
BertKing

@BertKing- return mHost != null && mAdded;これは、fragment.isAdded()メソッドの内部です。トレースするとmHostはアクティビティだと思いましたが、mHostはFragmentActivityの中にあるようです。だから、おそらく、あなたは正しい。追加はありますか?
ジョニーファイブ

14

非常に単純なソリューションである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.

}

12

例外: java.lang.IllegalStateException:フラグメント

DeadlineListFragment {ad2ef970}がアクティビティに添付されていません

カテゴリ:ライフサイクル

説明:時間のかかる操作をバックグラウンドスレッド(AsyncTaskなど)で実行すると、その間に新しいフラグメントが作成され、バックグラウンドスレッドが完了する前にアクティビティにデタッチされました。UIスレッドのコード(onPostExecuteなど)は、切り離されたFragmentを呼び出し、そのような例外をスローします。

解決策を修正:

  1. フラグメントを一時停止または停止するときにバックグラウンドスレッドをキャンセルする

  2. isAdded()を使用してフラグメントが添付されているかどうかを確認し、アクティビティからgetResources()を使用します。


11

私は遅れているかもしれませんが、誰かを助けるかもしれません.....これに対する最善の解決策は、グローバルアプリケーションクラスインスタンスを作成し、アクティビティがアタッチされていない特定のフラグメントでそれを呼び出すことです

以下のように

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;
    }
}

1
はい、この方法も広く使用されています。
CoolMind

1
これは賢明なオプションではありません。FragmentContextとApplicationContextのスタイルは異なります。フラグメントコンテキストには、さまざまなファイルから色、文字列リソースを取得する暗いテーマ、カスタムスタイル、ロケールなどがある場合があります。ApplicationContextは正しいリソースをプルしない場合があります。コンテキストがない場合は、そのリソースをレンダリングしようとしてはいけません。
Jemshit Iskenderov

2

このエラーは、インスタンス化できないフラグメントをインスタンス化する場合に発生する可能性があります。

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);

2

フラグメントを使用しisAdded() ている場合フラグメントが現在アクティビティにアタッチされている場合はtrueを返します。

アクティビティ内を確認したい場合

 Fragment fragment = new MyFragment();
   if(fragment.getActivity()!=null)
      { // your code here}
      else{
       //do something
       }

それが誰かを助けることを願って


1

私はこの問題を処理するために次のアプローチを採用しました。このようなアクティビティメソッドのラッパーとして機能する新しいクラスを作成しました

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として取得している場合は、いくつかのログを追加し、可能であればそれを修正してください。


0

これは、フラグメントにコンテキストがない場合に発生するため、getActivity()メソッドはnullを返します。取得する前にコンテキストを使用しているかどうか、またはActivityがもう存在していないかどうかを確認してください。fragment.onCreateでコンテキストを使用し、API応答の後に通常この問題が発生する


0

この例外は、サポートライブラリの実装のバグが原因で発生する場合があります。最近、私はそれを取り除くために26.1.0から25.4.0にダウングレードする必要がありました。


いいえ、ありませんが、作成する必要があるかもしれません。
Bord81

0

この問題は、使用できないコンテキストを呼び出すか、呼び出すときにnullを呼び出すたびに発生します。これは、バックグラウンドスレッドでメインアクティビティスレッドのコンテキストを呼び出すか、メインアクティビティスレッドでバックグラウンドスレッドのコンテキストを呼び出すときに発生する可能性があります。

たとえば、次のように共有設定文字列を更新しました。

editor.putString("penname",penNameEditeText.getText().toString());
editor.commit();
finish();

その直後にfinish()を呼び出しました。コミットがメインスレッドで実行され、完了するまで他の非同期コミットを停止すると、何が行われるかがわかります。したがって、そのコンテキストは書き込みが完了するまで存続します。したがって、以前のコンテキストはライブであり、エラーが発生します。

したがって、このコンテキストの問題があるコードがある場合は、コードを再確認してください。


どのようにしてこの問題を解決しましたか?私は非同期スレッド内で呼び出していますが、今この問題が発生しています。
Simon、

書き込み操作が完了したことを確認してください。その後、書き込み操作が完了する前ではなく、コンテキストのみが強制終了されます。
Prashant Paliwal 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.