Fragment's getView() returning null in a OnCli

2019-04-10 05:56发布

问题:

I'm using the support library and I have a Fragment (I'll call "MyFragment") implementing a method invoked by one of the Fragment's View during an OnClick event. The OnClickListener is set in the OnActivityCreate method like this:

@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
        }
    });
}

where showStuff() triggers a change in the Fragment's View, something as simple as updating the visibility of an item:

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

Everything works fine on my tests, and the same can be said about most of my users, however I have received today a single ANR report from Google Play developer's console, stating that the app crashed for a user with a NullPointerException on the line:

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

which means that:

ViewGroup base = (ViewGroup) getView();

returned null. This is the report:

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)

I have fixed the problem (or so I think, since I don't have a method of reproduction...) by just surrounding the offending lines with a:

if(base != null) {
}

my best guess is that the callback has been scheduled after onDestroyView has been called on MyFragment, thus resulting in getView() returning null.

Still, I'm quite puzzled by this bug, so I'd like your insights on the matter:

  1. assuming that my hypotesys is correct, is it normal for a OnClick callback to be executed when no layout is present, or can I regard this behavior as a bug (honestly: the view was obviously there when I clicked it, why should it die on me)?

  2. Is this problem related to the fact that I'm using the support library (last version, 13 May 2013)?

  3. If it's not a bug and I'm missing something, could you please point me to the relevant documentation?

Thank you for your attention!

回答1:

Up until Gingerbread there was a bug in the View click mechanism in that the callback for performing the click was not removed from the message queue when the View was detached from the Window. This has been fixed in ICS (or possibly in Honeycomb). Therefore if you're supporting Gingerbread or below, and your click listeners access other references that are removed when the Views are detached, then you should make sure to remove your click listeners upon detachment as well.

Note that this applies to all kinds of click listeners, not just OnClickListener. However it doesn't apply to long click listeners, as their callbacks were removed properly from the beginning.