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.