programing

getActivity()는 Fragment 함수에서 null을 반환합니다.

bestprogram 2023. 10. 9. 23:27

getActivity()는 Fragment 함수에서 null을 반환합니다.

이와 같은 공개적인 방법으로 프래그먼트(F1)가 있습니다.

public void asd() {
    if (getActivity() == null) {
        Log.d("yes","it is null");
    }
}

예, (Activity에서) 호출하면 null...

FragmentTransaction transaction1 = getSupportFragmentManager().beginTransaction();
F1 f1 = new F1();
transaction1.replace(R.id.upperPart, f1);
transaction1.commit();
f1.asd();

제가 아주 잘못하고 있는 게 분명한데 그게 뭔지 모르겠어요.

commit트랜잭션을 예약합니다. 즉, 즉시 발생하지는 않지만 다음에 메인 스레드가 준비되면 메인 스레드에서 작업으로 예약됩니다.

추가하는 게 좋을 것 같아요.

onAttach(Activity activity)

당신에게 방법Fragment그리고 그것에 중단점을 두고 당신의 전화와 관련하여 언제 호출되는지를 보는 것.asd(). 전화를 거는 방법 다음에 호출되는 것을 볼 수 있습니다.asd()출구. 더onAttach콜이 있는 곳입니다.Fragment그 활동과 이 시점부터 관련이 있습니다.getActivity()null이 아닌 값을 반환합니다(nb 또한 있습니다).onDetach()부름).

이 문제를 해결하는 최선의 방법은 onAttach가 호출될 때 활동 참조를 유지하고 필요한 경우 활동 참조를 사용하는 것입니다.

@Override
public void onAttach(Context context) {
    super.onAttach(activity);
    mContext = context;
}

@Override
public void onDetach() {
    super.onDetach();
    mContext = null;
}

당신이 전화했을 때 이런 일이 일어났습니다.getActivity()프래그먼트가 제거된 후에 마무리된 다른 스레드에서.대표적인 경우는 전화입니다.getActivity()(예전에)ToastHTTP 요청이 완료되었을 때(에서)onResponse예를 들어).

이를 방지하기 위해 필드 이름을 정의할 수 있습니다.mActivity대신에 사용합니다.getActivity(). 이 필드는 다음과 같이 fragment의 onAttach() 메서드에서 초기화할 수 있습니다.

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    if (context instanceof Activity){
        mActivity =(Activity) context;
    }
}

프로젝트에서는 보통 다음과 같은 기능을 사용하여 모든 프래그먼트에 대한 기본 클래스를 정의합니다.

public abstract class BaseFragment extends Fragment {

    protected FragmentActivity mActivity;

    @Override
public void onAttach(Context context) {
    super.onAttach(context);

    if (context instanceof Activity){
        mActivity =(Activity) context;
    }
}
}

해피코딩,

첨부 파일에서 활동을 참조할 것을 제안하는 다른 답변은 실제 문제에 대한 반창고를 제안하는 것입니다.getActivity가 null을 반환하면 Fragment가 Activity에 연결되어 있지 않음을 의미합니다.일반적으로 활동이 회전으로 인해 사라지거나 활동이 완료되었지만 조각에는 가비지 수집을 방지하는 일종의 콜백 수신기가 등록되어 있을 때 발생합니다.활동을 수행해야 하는데 활동이 사라진 경우 청취자가 호출되면 수행할 수 있는 작업이 거의 없습니다.당신의 코드에서 당신은 단지 확인해야 합니다.getActivity() != null없으면 아무것도 하지 말아요사라진 활동에 대한 참조를 유지하면 활동이 가비지 수집되는 것을 방지하게 됩니다.사용자가 시도할 수 있는 UI 작업은 사용자에게 표시되지 않습니다.저는 콜백 청취자가 UI와 관련이 없는 것에 대해 컨텍스트를 갖길 원하는 상황을 상상할 수 있습니다. 그러한 경우 애플리케이션 컨텍스트를 얻는 것이 더 합리적일 수 있습니다.참고로, 유일한 이유는onAttach트릭은 일반적으로 콜백 청취자가 실행한 후에는 더 이상 필요가 없으며 프래그먼트, 모든 보기 및 액티비티 컨텍스트와 함께 가비지 컬렉션이 될 수 있기 때문에 메모리 유출이 크지 않습니다.네가 만약setRetainInstance(true)활동 필드도 유지되지만 회전 후에는 현재 활동이 아닌 이전 활동이 될 수 있기 때문에 메모리 누수가 발생할 가능성이 더 높습니다.

Android API 레벨 23 이후 onAttach(Activity 액티비티)가 더 이상 사용되지 않습니다.첨부파일(Context context)에서 사용해야 합니다.http://developer.android.com/reference/android/app/Fragment.html#onAttach(android.app.Activity)

액티비티는 컨텍스트이므로 컨텍스트가 액티비티인지 확인하고 필요한 경우 해당 컨텍스트를 캐스트할 수 있습니다.

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    Activity a;

    if (context instanceof Activity){
        a=(Activity) context;
    }

}

PJL이 맞습니다.나는 그의 제안을 이용했고 이것이 내가 한 일입니다.

  1. fragment에 대해 정의된 전역 변수:

    private final Object attachingActivityLock = new Object();

    private boolean syncVariable = false;

  2. 실시한

@Override
public void onAttach(Activity activity) {
  super.onAttach(activity);
  synchronized (attachingActivityLock) {
      syncVariable = true;
      attachingActivityLock.notifyAll();
  }
}

3. 나는 getActivity()를 호출해야 하는 내 함수를 스레드로 마무리했습니다. 만약 그것이 메인 스레드에서 실행된다면, 나는 4단계로 스레드를 차단할 것이고, 첨부파일()에서는 절대 호출되지 않을 것이기 때문입니다.

    Thread processImage = new Thread(new Runnable() {

        @Override
        public void run() {
            processImage();
        }
    });
    processImage.start();

4. getActivity()를 호출해야 하는 내 기능에서, 나는 이것을 사용합니다(call getActivity()를 호출하기 전에).

    synchronized (attachingActivityLock) {
        while(!syncVariable){
            try {
                attachingActivityLock.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

UI 업데이트가 있으면 UI 스레드에서 실행해야 합니다.ImgeView를 업데이트해야 하므로 다음 작업을 수행했습니다.

image.post(new Runnable() {

    @Override
    public void run() {
        image.setImageBitmap(imageToShow);
    }
});

commit() 뒤에 콜백이 호출되는 순서:

  1. 커밋 직후 수동으로 호출하는 방법()
  2. 첨부파일()에
  3. CreateView()에서
  4. on ActivityCreated()

뷰(View)와 관련된 작업을 수행해야 했기 때문에 곧 첨부 파일()이 제게 적합하지 않았습니다. 충돌이 발생했습니다.그래서 commit() 직후(1.)라는 메서드 안에서 일부 매개 변수를 설정하고 있던 코드의 일부를 CreateView(3.)에서 내부 보기를 처리하는 코드의 다른 일부를 이동했습니다.

저는 OkHttp를 사용하고 있는데 방금 이 문제에 직면했습니다.


1부 @thucnguyen은 올바른 길을 가고 있었습니다.

이 문제는 조각이 제거된 후 완료된 다른 스레드에서 getActivity()를 호출할 때 발생했습니다.일반적인 경우는 HTTP 요청이 완료되었을 때 getActivity()(예: onResponse)를 호출하는 것입니다.

일부 HTTP 호출은 활동이 종료된 후에도 실행되고 있었습니다(HTTP 요청이 완료되는 데 시간이 걸릴 수 있기 때문입니다).그 다음에, 그다음에.HttpCallback부 Fragment했고를 .null 시도 시 getActivity().

http.newCall(request).enqueue(new Callback(...
  onResponse(Call call, Response response) {
    ...
    getActivity().runOnUiThread(...) // <-- getActivity() was null when it had been destroyed already

IMO 솔루션은 조각이 더 이상 살아있지 않을콜백이 발생하는 것을 방지하는 것입니다(Okhttp뿐만 아니라).

해결책: 예방.

프래그먼트 라이프사이클(자세한 정보는 여기)을 살펴보면 다음과 같은 것이 있습니다.onAttach(Context context)그리고.onDetach()방법들. 됩니다.이러한 메시지는 프래그먼트가 활동에 속한 후 각각 활동을 중지하기 직전에 호출됩니다.

은 우리가 그 것을 수 합니다.onDetach방법.

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    // Initialize HTTP we're going to use later.
    http = new OkHttpClient.Builder().build();
}

@Override
public void onDetach() {
    super.onDetach();

    // We don't want to receive any more information about the current HTTP calls after this point.
    // With Okhttp we can simply cancel the on-going ones (credits to https://github.com/square/okhttp/issues/2205#issuecomment-169363942).
    for (Call call : http.dispatcher().queuedCalls()) {
        call.cancel();
    }
    for (Call call : http.dispatcher().runningCalls()) {
        call.cancel();
    }
}

이 기능은 어디서 부르십니까?면 요.Fragment야, null.

그냥 전화하세요.getActivity()n일 때onCreateView()실행됩니다.

다음과 같이 하십시오.당신에게 도움이 될 것 같습니다.

private boolean isVisibleToUser = false;
private boolean isExecutedOnce = false;


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View root = inflater.inflate(R.layout.fragment_my, container, false);
    if (isVisibleToUser && !isExecutedOnce) {
        executeWithActivity(getActivity());
    }
    return root;
}

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    this.isVisibleToUser = isVisibleToUser;
    if (isVisibleToUser && getActivity()!=null) {
        isExecutedOnce =true;
        executeWithActivity(getActivity());
    }
}


private void executeWithActivity(Activity activity){
    //Do what you have to do when page is loaded with activity

}

아직 onAttach(Activity activity)에 문제가 있는 분들은 방금 Context로 변경되었습니다 -

    @Override
public void onAttach(Context context) {
    super.onAttach(context);
    this.context = context;
}

대부분의 경우 컨텍스트를 저장하면 충분합니다. 예를 들어 리소스()를 가져오려는 경우 컨텍스트에서 바로 저장할 수 있습니다.상황을 활동에 맞게 만들어야 할 경우에는 다음과 같이 하십시오.

 @Override
public void onAttach(Context context) {
    super.onAttach(context);
    mActivity a; //Your activity class - will probably be a global var.
    if (context instanceof mActivity){
        a=(mActivity) context;
    }
}

사용자 1868713에 의해 제안된 바와 같이.

또 다른 좋은 솔루션은 MVVM 아키텍처와 함께 Android의 LiveData를 사용하는 것입니다.ViewModel 내부에서 LiveData 개체를 정의하고 조각에서 이 개체를 관찰하게 되는데, LiveData 값이 변경되면 조각이 활성 상태에 있는 경우에만 관찰자에게 알림(이 경우 조각)되므로 조각이 활성 상태에 있는 경우에만 UI가 작동하고 작업에 액세스할 수 있습니다.LiveData와 함께 제공되는 이점 중 하나입니다.

물론 이 질문이 처음 나왔을 때는 LiveData가 없었습니다.제가 보기에 아직도 이 문제가 있고 누군가에게 도움이 될 수도 있기 때문에 여기에 답을 남깁니다.

onActivityCreated() 메서드 내의 호출 getActivity() 메서드

저는 이런 식으로 제 문제를 해결했습니다.이전 클래스에서 getApplicationContext에 이미 액세스할 수 있는 getApplicationContext를 통과했습니다.Inputstream 개체를 새 클래스의 Nutrients에 전달했습니다.

try{
                    InputStream is= getApplicationContext().getAssets().open("nutrient_list.json");
                    Nutrients nutrients=Nutrients.getNutrients(topRecognition,is);

                  } catch (IOException e) {
                    e.printStackTrace();
                  }

null Activity를 얻지 못하도록 보장하는 일반적인 메서드를 작성합니다.

public class BaseFragment extends Fragment {
    private Context contextNullSafe;

     @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
         /*View creation related to this fragment is finished here. So in case if contextNullSafe is null
         * then we can populate it here.In some discussion in - https://stackoverflow.com/questions/6215239/getactivity-returns-null-in-fragment-function
         * and https://stackoverflow.com/questions/47987649/why-getcontext-in-fragment-sometimes-returns-null,
         * there are some recommendations to call getContext() or getActivity() after onCreateView() and
         * onViewCreated() is called after the onCreateView() call every time */
        if (contextNullSafe == null) getContextNullSafety();
    }


   @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        contextNullSafe = context;
    }

    /**CALL THIS IF YOU NEED CONTEXT*/
    public Context getContextNullSafety() {
                if (getContext() != null) return getContext();
                if (getActivity() != null) return getActivity();
                if (contextNullSafe != null) return contextNullSafe;
                if (getView() != null && getView().getContext() != null) return getView().getContext();
                if (requireContext() != null) return requireContext();
                if (requireActivity() != null) return requireActivity();
                if (requireView() != null && requireView().getContext() != null)
                    return requireView().getContext();
                
                return null;
            
        }

    /**CALL THIS IF YOU NEED ACTIVITY*/
    public FragmentActivity getActivityNullSafety() {
        if (getContextNullSafety() != null && getContextNullSafety() instanceof FragmentActivity) {
            /*It is observed that if context it not null then it will be
             * the related host/container activity always*/
            return (FragmentActivity) getContextNullSafety();
        }
        return null;
    }

언급URL : https://stackoverflow.com/questions/6215239/getactivity-returns-null-in-fragment-function