【问题标题】:Fragment's getView() returning null in a OnClickListener callbackFragment 的 getView() 在 OnClickListener 回调中返回 null
【发布时间】:2013-07-22 10:37:16
【问题描述】:

我正在使用支持库,并且我有一个 Fragment(我将称之为“MyFragment”)实现了一个在 OnClick 事件期间由 Fragment 的视图之一调用的方法。 OnClickListener 设置在 OnActivityCreate 方法如下:

@Override
public void onActivityCreated(Bundle inState) {
    super.onActivityCreated(inState);

    ViewGroup base = (ViewGroup) getView();
    TextView tv = (TextView) base.findViewById(R.id.monografiat);
    tv.setOnClickListener(new OnClickListener() {                            
        @Override
        public void onClick(View v) {
            showStuff(); // MyFragment:150
        }
    });
}

其中 showStuff() 会触发 Fragment 视图的更改,就像更新项目的可见性一样简单:

private void showStuff() {  //MyFragment:95
    ViewGroup base = (ViewGroup) getView();
    LinearLayout ll = (LinearLayout) base.findViewById(R.id.someview); // MyFragment:97
    ll.setVisibility(View.VISIBLE);
}

在我的测试中一切正常,对于我的大多数用户来说也是如此,但是我今天从 Google Play 开发者控制台收到了一份 ANR 报告,指出该应用程序因用户崩溃而出现 NullPointerException行:

LinearLayout ll = (LinearLayout) base.findViewById(R.id.someview);

这意味着:

ViewGroup base = (ViewGroup) getView();

返回空值。这是报告:

java.lang.NullPointerException
    at mypackage.MyFragment.showStuff(MyFragment.java:97)
    at mypackage.MyFragment.access$0(MyFragment.java:95)
    at mypackage.MyFragment$2.onClick(MyFragment.java:150)
    at android.view.View.performClick(View.java:2538)
    at android.view.View$PerformClick.run(View.java:9152)
    at android.os.Handler.handleCallback(Handler.java:587)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:123)
    at android.app.ActivityThread.main(ActivityThread.java:3687)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
    at dalvik.system.NativeStart.main(Native Method)

我已经解决了这个问题(或者我认为,因为我没有复制的方法......)只是用一个:

if(base != null) {
}

我最好的猜测是回调已经安排在在 MyFragment 上调用 onDestroyView 之后,因此导致 getView() 返回 null。

不过,我还是对这个错误感到很困惑,所以我想请你对此事发表见解:

  1. 假设我的 hypotesys 是正确的,在没有布局时执行 OnClick 回调是否正常,或者我可以将此行为视为错误(老实说:当我单击视图时,视图显然就在那里,为什么要死在我身上)?

  2. 这个问题是否与我正在使用支持库(最新版本,2013 年 5 月 13 日)有关?

  3. 如果这不是错误并且我遗漏了一些东西,请您指出相关文档吗?

感谢您的关注!

【问题讨论】:

  • 您使用ViewGroup 代替View 的任何原因?您是否还可以检查R.id.someview 是否在getView() 返回的视图中定义?
  • 不是在这个特殊场合,但是我知道布局是 ViewGroup 的子类(否则 Java 会抛出 ClassCastException)。至于 R.id.someview,如果找不到对应的视图,则会在第 98 行(而不是第 97 行)抛出异常
  • 你说得对,我完全错过了。
  • nop:还是谢谢你
  • onActivityCreated() 回调是针对MyFragment 的,对吗?此外,onActivityCreated() 中使用的 base 变量是 ...?

标签: android android-fragments android-lifecycle android-support-library


【解决方案1】:

在 Gingerbread 之前,View 点击机制中存在一个错误,即当ViewWindow 分离时,执行点击的回调并未从消息队列中移除。这已在 ICS(或可能在 Honeycomb)中得到修复。因此,如果您支持 Gingerbread 或更低版本,并且您的点击侦听器访问在分离 Views 时移除的其他引用,那么您应该确保在分离时也移除您的点击侦听器。

请注意,这适用于所有类型的点击侦听器,而不仅仅是OnClickListener。但是它不适用于长点击监听器,因为它们的回调从一开始就被正确删除了。

【讨论】:

  • 这完全符合问题(可惜我在开发相关应用程序时没有发现这一点...... :| ):您能否提供一些有关此问题的权威来源?然后我会将您的答案标记为解决方案。谢谢
  • 我不知道有任何旧的错误报告可供参考,但最权威的来源是source ;)
  • 我明白了:粗略看,当窗口失去焦点时,我会说问题出在第 5843 行(缺少“removeTapCallback”)。干得好,真的!谢谢!
  • 实际上真正的修复在第 #9796 行,在 onDetachedFromWindow() 回调中的其他回调删除中包含了 removePerformClickCallback()。我链接到 diff 的那部分,但它仅在页面完全加载时跳转到该部分。不客气——即使你通过支持和接受我的回答让我通过无名英雄徽章重新开始寻找寻宝者的帽子:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-07
  • 1970-01-01
  • 1970-01-01
  • 2014-04-30
相关资源
最近更新 更多