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

이 오류는 두 가지 요소의 결합 된 효과로 인해 발생합니다.

  • HTTP 요청이 완료되면가 여전히 포 그라운드에 있는지 여부를 모르고 onResponse()또는 onError()(메인 스레드에서 작동하는) 호출을 호출합니다 Activity. 이 경우 Activity(사용자가 다른 곳에서 탐색) 사라, getActivity()NULL을 반환합니다.
  • 발리 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내에서들 Activity, '피하기 NPEs에 아주 간단한 방법이 없습니다. Activity스레드 중 하나가 백그라운드에서 무언가를 수행하는 동안 사용자가 현재에서 벗어날 수있는 기회는 항상 있으며 스레드가 완료 onPostExecute()되거나 onResponse()호출 될 때 없습니다 Activity. 코드의 다양한 지점에서 null 참조를 확인하기 만하면됩니다. :)
— YS

2
안드로이드 원숭이 테스트 (adb shell monkey)는 일반적인 / 전역 방식 으로이 오류를 설명하지 않은 경우이 오류를 근절하는 데 실제로 좋습니다.
— Groovee60

5
i Visit ()로 충분합니다. 최종 공개 부울 iBoolean () {return mActivity! = null && mAdded; }
— lannyf

2
@ruselli : added부울 플래그와 현재 Activity인스턴스의 유무를 확인합니다 null.
— YS

1
@gauravjain Fragments에서 직접 HTTP 요청과 같은 비동기 요청을하지 마십시오. 활동에서 수행하면 괜찮습니다. 또한 FragmentManager에서 명확한 Fragment 참조를 사용하는 것이 좋으며 메모리 누수를 피하는 가장 좋은 방법입니다.
— YS

56

조각 수명주기는 매우 복잡하고 버그로 가득차 있습니다.

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

2
어디에 두어야합니까?
— Vaclovas Rekašius Jr.

1
@ VaclovasRekašiusJr. 프래그먼트 내부에서 액티비티에 액세스하려는 거의 모든 위치와 같습니다. 장난!
— TylerJames

2
activity == null 인 경우 어떻게해야합니까? 내 응용 프로그램을 유지하려면 @Miroslav
— pavel

i Visit ()를 살펴보면 "activity! = null"이 중복되지 않는다는 것을 알 수 있습니다.
— BertKing

@BertKing- return mHost != null && mAdded;이것이 fragment.iPart () 메소드의 내부 내용입니다. 추적하면 mHost가 Activity라고 생각했지만 mHost가 FragmentActivity 안에있는 것처럼 보입니다. 아마, 당신 말이 맞을 것입니다. 추가 사항이 있습니까?
— Johnny Five

14

매우 간단한 해결책을 찾았습니다. 현재 조각이 해당 활동에 첨부되어 있는지 여부를 식별하는 조각 방법 중 하나 인 iBug () 메서드입니다.

우리는 다음과 같이 프래그먼트 클래스의 모든 곳에서 이것을 사용할 수 있습니다 :

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. 조각이 첨부되어 있는지 확인한 후 활동에서 getResources ()를 확인하려면 i Visit ()를 사용하십시오.


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는 스타일이 다릅니다. Fragment Context에는 어두운 테마, 사용자 정의 스타일, 로케일 등이있을 수 있습니다. 다른 파일에서 색상, 문자열 리소스를 가져옵니다. 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 () 메소드는 널을 리턴합니다. 컨텍스트를 얻기 전에 컨텍스트를 사용하는지 확인하거나 활동이 더 이상 존재하지 않는지 확인하십시오. 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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.