getActivity()在Fragment函数中返回null

Luk*_*kap 182 null android android-context android-fragments android-activity

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

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

是的,当我调用它(来自Activity)时,它是null ...

FragmentTransaction transaction1 = getSupportFragmentManager().beginTransaction();
F1 f1 = new F1();
transaction1.replace(R.id.upperPart, f1);
transaction1.commit();
f1.asd();
Run Code Online (Sandbox Code Playgroud)

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

PJL*_*PJL 162

commit 调度事务,即它不会立即发生,而是在下一次主线程准备好时安排在主线程上工作.

我建议添加一个

onAttach(Activity activity)
Run Code Online (Sandbox Code Playgroud)

你的方法,Fragment并在它上面设置一个断点,并查看它相对于你的呼叫被调用的时间asd().您将看到在调用asd()退出的方法之后调用它.该onAttach呼叫在Fragment连接到它的活动,从这个角度getActivity()将返回非空(NB也有一个onDetach()呼叫).

  • onAttach(活动动态)似乎已经贬值..任何解决方法 (6认同)
  • 我不明白你如何解决你的问题.如果我的getActivity()没有准备就绪,我怎样才能获得FragmentActivity对象的引用? (4认同)
  • API 24引入了`commitNow()` (3认同)
  • @Vivek我不太清楚你想要实现的目标.如果你需要片段直接显示一个对话框,那么让它做它在创建时需要做的事情,例如在它的`onCreateView`或`onActivityCreated`方法中.我质疑为什么asd()需要在问题发布时调用. (2认同)
  • onAttach已弃用 (2认同)

Paw*_*ari 91

最好摆脱这个是在调用onAttach时保持活动参考,并在需要的地方使用活动参考,例如

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

@Override
public void onDetach() {
    super.onDetach();
    mContext = null;
}
Run Code Online (Sandbox Code Playgroud)

  • 我们应该在onDetach()上设置mActivity = null吗? (33认同)
  • 如果我们不在`onDestroy()`中取消它,我们是否泄漏了`Activity`? (8认同)
  • @OliverPearmain如果你将在onDetach()中进行,那么就没有利润了.你必须在onDestory()中使它无效.此外,你必须在WeakRefernce中持有它. (5认同)
  • 根据http://developer.android.com/intl/zh-tw/guide/components/fragments.html,在调用onCreateView()之前调用onAttach().但是当我在onCreateView()中调用getActivity()时,我仍然得到一个NullPointerException.怎么会发生这种情况? (2认同)

thu*_*yen 77

当您getActivity()在删除片段后调用另一个完成的线程时,会发生这种情况.典型的情况是在HTTP请求完成时调用getActivity()(例如,用于a Toast)(onResponse例如).

为避免这种情况,您可以定义字段名称mActivity而不是使用它getActivity().该字段可以在Fragment的onAttach()方法中初始化,如下所示:

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

    if (context instanceof Activity){
        mActivity =(Activity) context;
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的项目中,我通常使用此功能为我的所有片段定义基类:

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;
    }
}
}
Run Code Online (Sandbox Code Playgroud)

快乐的编码,

  • 我们应该设置mActivity = null; 在onDetach()? (18认同)
  • 这将泄漏而不会使活动无效. (5认同)
  • @BharatDodeja应该在onDetach上设置mActivity = null吗?你知道了吗? (4认同)

mig*_*uel 22

其他答案表明在onAttach中保留对活动的引用只是建议对真正的问题进行绑定.当getActivity返回null时,表示Fragment未附加到Activity.最常见的情况是,当Activity因旋转或Activity完成而消失时,会发生这种情况,但Fragment具有某种回调侦听器.如果您需要对Activity执行某些操作但是Activity已经消失,那么当调用者被调用时,您无能为力.在您的代码中,您应该检查getActivity() != null,如果它不存在,那么不要做任何事情.如果您保留对活动的引用,那么您将阻止活动被垃圾回收.用户不会看到您可能尝试执行的任何UI操作.我可以想象一些情况,在回调监听器中你可能想要一个非UI相关的上下文,在这种情况下,获取Application上下文可能更有意义.请注意,onAttach诀窍不是大内存泄漏的唯一原因是因为通常在回调侦听器执行之后它将不再需要,并且可以与Fragment,其所有View和Activity上下文一起被垃圾收集.如果你setRetainInstance(true)有更大的内存泄漏的可能性,因为活动字段也将被保留,但在轮换后可能是前一个活动而不是当前活动.

  • 这正是我的问题。我有一个执行过程的片段 -> 然后显示一个广告 -> 然后过程继续。在从广告返回(通过侦听器到广告事件)后的某些设备中,getActivity() 为空。但是我需要继续做其他部分的工作才能完成工作。你的意思是没有办法解决这个问题吗? (3认同)

Sac*_*hin 16

自Android API级别23以来,onAttach(活动活动)已被弃用.您需要使用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;
    }

}
Run Code Online (Sandbox Code Playgroud)


zaj*_*.m2 10

PJL是对的.我已经使用了他的建议,这就是我所做的:

  1. 片段的已定义全局变量:

    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();
  }
}
Run Code Online (Sandbox Code Playgroud)

3.我把我的函数包装起来,我需要在线程中调用getActivity(),因为如果它在主线程上运行,我会用第4步阻塞线程,并且永远不会调用onAttach().

    Thread processImage = new Thread(new Runnable() {

        @Override
        public void run() {
            processImage();
        }
    });
    processImage.start();
Run Code Online (Sandbox Code Playgroud)

4.在我需要调用getActivity()的函数中,我使用它(在调用getActivity()之前)

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

如果您有一些UI更新,请记住在UI线程上运行它们.我需要更新ImgeView,所以我做了:

image.post(new Runnable() {

    @Override
    public void run() {
        image.setImageBitmap(imageToShow);
    }
});
Run Code Online (Sandbox Code Playgroud)


Bog*_*rac 7

commit()之后调用回调的顺序:

  1. 无论你在commit()之后手动调用什么方法
  2. onAttach()
  3. onCreateView()
  4. onActivityCreated()

我需要做一些涉及一些视图的工作,所以onAttach()对我不起作用; 它崩溃了.所以我移动了部分代码,它在commit()(1)之后的一个方法中设置了一些参数,然后在onCreateView()(3.)中处理视图的另一部分代码.