我有一个片段(F1)与这样的公共方法

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

是的,当我调用它(从活动),它是空…

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

一定是我做错了什么,但我不知道是什么。


当前回答

The other answers that suggest keeping a reference to the activity in onAttach are just suggesting a bandaid to the real problem. When getActivity returns null it means that the Fragment is not attached to the Activity. Most commonly this happens when the Activity has gone away due to rotation or the Activity being finished but the Fragment still has some kind of callback listener registered preventing it from being garbage collected. When the listener gets called if you need to do something with the Activity but the Activity is gone there isn't much you can do. In your code you should just check getActivity() != null and if it's not there then don't do anything. If you keep a reference to the Activity that is gone you are preventing the Activity from being garbage collected. Any UI things you might try to do won't be seen by the user. I can imagine some situations where in the callback listener you want to have a Context for something non-UI related, in those cases it probably makes more sense to get the Application context. Note that the only reason that the onAttach trick isn't a big memory leak is because normally after the callback listener executes it won't be needed anymore and can be garbage collected along with the Fragment, all its View's and the Activity context. If you setRetainInstance(true) there is a bigger chance of a memory leak because the Activity field will also be retained but after rotation that could be the previous Activity not the current one.

其他回答

在哪里调用这个函数?如果在Fragment的构造函数中调用它,它将返回null。

当onCreateView()方法被执行时,只需调用getActivity()。

自Android API级别23起,onAttach(Activity Activity)已弃用。你需要使用onAttach(Context Context)。http://developer.android.com/reference/android/app/Fragment.html onAttach (android.app.Activity)

Activity是一个上下文,所以如果你可以简单地检查上下文是否是一个Activity,并在必要时强制转换它。

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

    Activity a;

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

}

The other answers that suggest keeping a reference to the activity in onAttach are just suggesting a bandaid to the real problem. When getActivity returns null it means that the Fragment is not attached to the Activity. Most commonly this happens when the Activity has gone away due to rotation or the Activity being finished but the Fragment still has some kind of callback listener registered preventing it from being garbage collected. When the listener gets called if you need to do something with the Activity but the Activity is gone there isn't much you can do. In your code you should just check getActivity() != null and if it's not there then don't do anything. If you keep a reference to the Activity that is gone you are preventing the Activity from being garbage collected. Any UI things you might try to do won't be seen by the user. I can imagine some situations where in the callback listener you want to have a Context for something non-UI related, in those cases it probably makes more sense to get the Application context. Note that the only reason that the onAttach trick isn't a big memory leak is because normally after the callback listener executes it won't be needed anymore and can be garbage collected along with the Fragment, all its View's and the Activity context. If you setRetainInstance(true) there is a bigger chance of a memory leak because the Activity field will also be retained but after rotation that could be the previous Activity not the current one.

编写一个通用方法,确保永远不会得到空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;
    }

PJL是对的。 我采纳了他的建议,我是这样做的:

为fragment定义的全局变量: attachingActivityLock = new Object(); private boolean syncVariable = false; 实现

@Override onAttach(Activity Activity) { super.onAttach(活动); synchronized (attachingActivityLock) { syncVariable = true; attachingActivityLock.notifyAll (); } }

3.我在线程中包装了我的函数,在那里我需要调用getActivity(),因为如果它将在主线程上运行,我将用步骤4阻塞线程。onAttach()将永远不会被调用。

    Thread processImage = new Thread(new Runnable() {

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

4所示。在我的函数中,我需要调用getActivity(),我使用这个(在调用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);
    }
});