本文将介绍dialog fragment在使用过程中反复出现的问题。
当使用dialog fragment时,在重写了getDialog的dismiss的监听时。取消弹窗,退出页面,重新进入,会导致dialogfragment重新出现。
通过排查发现,若代码中主动调用了dismiss,则不会出现该bug,否则会出现这种情况。
对于出现这种情况的原因,可以追查源码发现如下:
(一)首先,观察setOnDismissListener是一个单对象监听,换而言之,重写会进行覆盖。
/**
* Set a listener to be invoked when the dialog is dismissed.
* @param listener The {@link DialogInterface.OnDismissListener} to use.
*/
public void setOnDismissListener(@Nullable OnDismissListener listener) {
if (mCancelAndDismissTaken != null) {
throw new IllegalStateException(
"OnDismissListener is already taken by "
+ mCancelAndDismissTaken + " and can not be replaced.");
}
if (listener != null) {
mDismissMessage = mListenersHandler.obtainMessage(DISMISS, listener);
} else {
mDismissMessage = null;
}
}
(二)第二,追查dialogfragment的源码,发现有以下代码:
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (!mShowsDialog) {
return;
}
View view = getView();
if (view != null) {
if (view.getParent() != null) {
throw new IllegalStateException(
"DialogFragment can not be attached to a container view");
}
mDialog.setContentView(view);
}
final Activity activity = getActivity();
if (activity != null) {
mDialog.setOwnerActivity(activity);
}
mDialog.setCancelable(mCancelable);
mDialog.setOnCancelListener(this);
mDialog.setOnDismissListener(this);
if (savedInstanceState != null) {
Bundle dialogState = savedInstanceState.getBundle(SAVED_DIALOG_STATE_TAG);
if (dialogState != null) {
mDialog.onRestoreInstanceState(dialogState);
}
}
}
发现在onActivityCreated方法中,会调用一次setOnDismissListener。假如我们重写的基类中,且在onActivityCreated生命周期后,通过getDialog()方法重写了setOnDismissListener,那么原始的dialog定义好的setOnDismissListener就会失效,导致文章开始说的bug出现。
这里解决方法有很多,提供一下思路:
(一)如果外部一定要设置dialog的setOnDismissListener监听,这个时候,需要在该方法内,调用一次dismiss()方法确保dialog fragment真正走了"消失"的方法。
(二)子类重写onDismiss()方法,该方法是DialogInterface.OnDismissListener的实现方法,当dialog取消的时候,会进行回调。
总的来所,推荐使用第二种方法,能减少意外情况发生。
that's all--------------------------------------------------------------------------------------