一、 前述
DialogFragment从名字上来就可以理解:它是fragment,具有dialog的特性。
二、 方案
关于显示可以使用FragmentTransaction,因为它本身是Fragment。
关于dismiss:
@Override
public void onDismiss(@NonNull DialogInterface dialog) {
if (!mViewDestroyed) {
// Note: we need to use allowStateLoss, because the dialog
// dispatches this asynchronously so we can receive the call
// after the activity is paused. Worst case, when the user comes
// back to the activity they see the dialog again.
dismissInternal(true, true);
}
}
void dismissInternal(boolean allowStateLoss, boolean fromOnDismiss) {
if (mDismissed) {
return;
}
mDismissed = true;
mShownByMe = false;
if (mDialog != null) {
// Instead of waiting for a posted onDismiss(), null out
// the listener and call onDismiss() manually to ensure
// that the callback happens before onDestroy()
mDialog.setOnDismissListener(null);
mDialog.dismiss();
if (!fromOnDismiss) {
// onDismiss() is always called on the main thread, so
// we mimic that behavior here. The difference here is that
// we don't post the message to ensure that the onDismiss()
// callback still happens before onDestroy()
if (Looper.myLooper() == mHandler.getLooper()) {
onDismiss(mDialog);
} else {
mHandler.post(mDismissRunnable);
}
}
}
mViewDestroyed = true;
if (mBackStackId >= 0) {
requireFragmentManager().popBackStack(mBackStackId,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
mBackStackId = -1;
} else {
FragmentTransaction ft = requireFragmentManager().beginTransaction();
ft.remove(this);
if (allowStateLoss) {
ft.commitAllowingStateLoss();
} else {
ft.commit();
}
}
}
可以发现,如果使用DialogFragment.dismiss()
方法或者按键回退触发dismiss都会调用dismissInternal(true, true);
最终都会调用FragmentTransaction.remove(this)
,这就是销毁了fragment。很多情况下,需要保留弹窗状态的,而此时就不满足要求了。
——>所以可以覆写onDismiss方法。
@Override
public void onDismiss(DialogInterface dialog) {
//注释掉super方法调用,因为该方法会使得Fragment销毁
// super.onDismiss(dialog);
}
查看源码可以发现DialogFragment其实是:Dialog中包裹了Fragment。
那么其显示隐藏其实是可以直接使用dialog.show()
or dialog.hide()
来实现的。
使用getDialog().hide()
后,息屏再打开时结果整个弹窗重新出现了,原因如下:
@Override
public void onStart() {
super.onStart();
if (mDialog != null) {
mViewDestroyed = false;
mDialog.show();
}
}
@Override
public void onStop() {
super.onStop();
if (mDialog != null) {
mDialog.hide();
}
}
如何屏蔽掉上面生命周期中的执行代码对dialog的影响?
手动在生命周期中show() or hide()
直接注释掉super.onStart()不可以么?
不可以,会导致生命周期紊乱。而且ide会爆红,因为这里api(Fragment)用了一个注解:@CallSuper
/**
* Called when the Fragment is visible to the user. This is generally
* tied to {@link Activity#onStart() Activity.onStart} of the containing
* Activity's lifecycle.
*/
@CallSuper
public void onStart() {
mCalled = true;
}
//追踪CallSuper定义
/**
* Denotes that any overriding methods should invoke this method as well.
* <p>
* Example:
* <pre><code>
* @CallSuper
* public abstract void onFocusLost();
* </code></pre>
*/
@Documented
@Retention(CLASS)
@Target({METHOD})
public @interface CallSuper {
}
可以发现,凡是被@CallSuper注解的方法,都必须在覆写的方法中回调。于是,无论如何都不能去掉super.onStart()
or super.onStop()
。
三、 结论
就案例中提到的需求而言,这样使用DialogFragment是比较繁琐的,还不如直接使用Dialog包裹Fragment。 对API不了解的情况下,还是慎用。
看完文章,如果有帮助,不忘点个赞or喜欢!