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 :
- https://stackoverflow.com/questions/12265611/dialogfragment-nullpointerexception-support-library/27084544#27084544
- https://stackoverflow.com/questions/28800754/dialogfragment-mysterious-null-pointer-exception
Comments
Post a Comment