Skip to main content

DialogFragment : NullPointerException (support library)


Another weird crash this time !

Here’s the stack trace :

Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo{<activity.fully.qualified.path>}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.app.Dialog.setContentView(android.view.View)' on a null object reference
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2659)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2724)
       at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4524)
       at android.app.ActivityThread.-wrap19(ActivityThread.java)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1479)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6123)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'void android.app.Dialog.setContentView(android.view.View)' on a null object reference
       at android.support.v4.app.DialogFragment.onActivityCreated(SourceFile:395)
       at android.support.v4.app.Fragment.performActivityCreated(SourceFile:2193)
       at android.support.v4.app.FragmentManagerImpl.moveToState(SourceFile:1323)
       at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(SourceFile:1523)
       at android.support.v4.app.FragmentManagerImpl.moveToState(SourceFile:1585)
       at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(SourceFile:2832)
       at android.support.v4.app.FragmentController.dispatchActivityCreated(SourceFile:201)
       at android.support.v4.app.FragmentActivity.onStart(SourceFile:603)
       at android.support.v7.app.AppCompatActivity.onStart(SourceFile:181)
       at in.zeta.android.ui.activity.BaseActivity.onStart(SourceFile:82)
       at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1270)
       at android.app.Activity.performStart(Activity.java:6689)
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2622)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2724)
       at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4524)
       at android.app.ActivityThread.-wrap19(ActivityThread.java)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1479)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6123)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)

When the activity is ready to start, the system fires the required lifecycle callbacks on the fragments to let them know that activity has been created and hence, onActivityCreated callback of the DialogFrament is called.

If you look at the source code, this function essentially initializes the dialog i.e. inflates its view, sets listeners and restores its state if required.

Problem?

After reading up on this crash, I found out that this crash happens in an inconsistent state when the system had failed to properly create the dialog (still trying to figure out when that happens :/ ). Hence, mDialog is null but mShowsDiaog is still true. So, that makes it think that the dialog is being shown properly whereas it isn’t. And therefore, it encounter a NullPointerException.

Solution

I haven’t yet found the scenarios where it occurs but a way to at least prevent the crash.

Here’s what we do :

We override the onActivityCreated callback for the dialogfragment and check there itself if we are in that inconsistent state. If we are, simply return from there.

In case you have multiple dialog fragments and you are not sure which one is causing this, instead of overriding the function in each one of them, define a BaseDialogFragment class which is extended by all of them.

Something like this :


public abstract class BaseDialogFragment extends DialogFragment {

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        if (getDialog() == null) {
            Context context = getContext();
            while (context instanceof ContextWrapper) {
                if (context instanceof FragmentActivity) {
                    break;
                }
                context = ((ContextWrapper) context).getBaseContext();
            }
            if (context instanceof FragmentActivity) {
                ((FragmentActivity) context).finish();
                return;
            } else {
                setShowsDialog(false);
            }
        }
        super.onActivityCreated(savedInstanceState);
    }
}

We use DialogFragments for showing dialogs only, that’s why if getDialog() is null, I call setShowsDialog(false);

Let me know in case of any doubts.

Cheers !

References :

Comments

Popular posts from this blog

Android : AbsSavedState cannot be cast to $SavedState

Android AbsSavedState cannot be cast to $SavedState I came across a strange crash today. This is the stacktrace : Fatal Exception: java.lang.ClassCastException: android.view.AbsSavedState$1 cannot be cast to android.widget.ScrollView$SavedState at android.widget.ScrollView.onRestoreInstanceState(ScrollView.java:1810) at android.view.View.dispatchRestoreInstanceState(View.java:14768) at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3123) at android.view.View.restoreHierarchyState(View.java:14746) at android.support.v4.app.Fragment.restoreViewState(SourceFile:470) at android.support.v4.app.FragmentManagerImpl.moveToState(SourceFile:1326) at android.support.v4.app.FragmentManagerImpl.moveFragmentsToInvisible(SourceFile:2323) at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(SourceFile:2136) at android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(SourceFile:2092) at androi...

Android Tip : Handling back button in Fragments

Android Tip : Handling hardware back button in Fragment and DialogFragment This post explains how to handle hardware back button in a Fragment OR DialogFragment . In DialogFragment, it’s quiet straight forward to achieve this. You’ve to get the dialog instance and set onKeyListener on it : if (getDialog() != null ) { getDialog().setOnKeyListener( new DialogInterface.OnKeyListener() { @Override public boolean onKey (DialogInterface dialog, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) { Timber.i( "hardware back button pressed" ); } } }); } This can be done in the onViewCreated callback. For fragments, this method doesn’t work and fragments doesn’t have a direct callback to catch this event. So in this case, the approach that we follow is : You...

Android Material Showcase View - Part 1

In this series, I'll be talking about a library which is used by a lot of android developers for showcasing their in-app content,  MaterialShowcaseView . I used this library sometime back for my work and had to modify it to fit my needs. In this process, I ended up digging it a lot and would like to share what I learned. The original library offers a fix set of features, which are demonstrated by the screenshots in the README. Let's jump on the technicalities right away. The original library offers two things : 1) highlighting a view ( see the README to know what I mean by highlighting here) 2) showing a content box that tells user what the highlighted view is about. Here's how it does this : The library adds a direct view child ( this class ) in the window decor view, so that it's drawn on top of your activity's view ( here ). Then, for drawing the overlay and highlighting our view, it overrides the `onDraw()` method of this view and uses android...