持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情
前言
在开始学习 Android 的时候,制作对话框,无疑都是直接使用 Dialog,然后对其进行自定义,而后面推出 DialogFragment 后,更多人都开始使用 DialogFragment 了,那么,DialogFragment 与 Dialog 到底有什么区别?
首先,我们来分析下 DialogFragment。
DialogFragment 生命周期
public class DialogFragment extends Fragment
implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
可以看得出,DialogFragment 是继承于 Fragment 的,也就是说 DialogFragment 的执行过程其实就是 Fragment 生命周期的执行过程。
那么我们来初步回顾下 Fragment 的生命周期。
- onAttach
- onCreate
- onCreateView
- onActivityCreated
- onStart
- onResume
- onPause
- onStop
- onDestroyView
- onDestroy
- onDetach
至于这些生命周期的含义就不说明了,网上有很多文章,这个也不是本文的重点。
我们从上往下进行排查:
onAttach
public void onAttach(@NonNull Context context) {
super.onAttach(context);
getViewLifecycleOwnerLiveData().observeForever(mObserver);
if (!mShownByMe) {
mDismissed = false;
}
}
private Observer<LifecycleOwner> mObserver = new Observer<LifecycleOwner>() {
public void onChanged(LifecycleOwner lifecycleOwner) {
if (lifecycleOwner != null && mShowsDialog) {
View view = requireView();
···
if (mDialog != null) {
···
mDialog.setContentView(view);
}
}
}
};
其实就是对 Fragment 进行生命周期的监听,当 Dialog 在展示的时候,更改 Dialog 的视图。
onCreate
public void onCreate(@Nullable Bundle savedInstanceState) {
···
mHandler = new Handler();
mShowsDialog = mContainerId == 0;
if (savedInstanceState != null) {
mStyle = savedInstanceState.getInt(SAVED_STYLE, STYLE_NORMAL);
mTheme = savedInstanceState.getInt(SAVED_THEME, 0);
mCancelable = savedInstanceState.getBoolean(SAVED_CANCELABLE, true);
mShowsDialog = savedInstanceState.getBoolean(SAVED_SHOWS_DIALOG, mShowsDialog);
mBackStackId = savedInstanceState.getInt(SAVED_BACK_STACK_ID, -1);
}
}
主要是初始化,并且还原之前存储的数据。
onCreateView
没有实现。
onActivityCreated
没有实现。
onStart
public void onStart() {
super.onStart();
if (mDialog != null) {
mViewDestroyed = false;
mDialog.show();
// Only after we show does the dialog window actually return a decor view.
View decorView = mDialog.getWindow().getDecorView();
ViewTreeLifecycleOwner.set(decorView, this);
ViewTreeViewModelStoreOwner.set(decorView, this);
ViewTreeSavedStateRegistryOwner.set(decorView, this);
}
}
主要是将 Dialog 展示出来。
onResume
没有实现。
onPause
没有实现。
onStop
public void onStop() {
super.onStop();
if (mDialog != null) {
mDialog.hide();
}
}
将 Dialog 进行关闭。
onDestroyView
public void onDestroyView() {
super.onDestroyView();
if (mDialog != null) {
mViewDestroyed = true;
mDialog.setOnDismissListener(null);
mDialog.dismiss();
if (!mDismissed) {
onDismiss(mDialog);
}
mDialog = null;
mDialogCreated = false;
}
}
再次确认关闭 Dialog,并且对数据进行清空。
onDestroy
没有实现。
onDetach
没有实现。
从上面的生命周期的分析,其实我们可以看出,DialogFragment 其实是利用 Fragment 的生命周期对 Dialog 进行管控的,方便 Dialog 的创建到销毁的流程管控。
Dialog 和 Fragment 的绑定关系
可能有些同学就有疑问了,通过上面的讲解,并没有实际性看出 Dialog 和 Fragment 的绑定关系啊,为什么我给 Fragment 设置 UI,会展示到 Dialog 中?
这是因为我们在创建 Fragment 的时候,总会重载其 onCreateView
方法,在里面进行布局的设置,而在 onAttach
中,我们讲过监听了 Fragment 的生命周期,而 Fragment 的生命周期改变的时候,若 Dialog 在 show 的状态,就会把 Fragment 的布局效果设置给 Dialog,这就完成了 Dialog 和 Fragment 的绑定。
Dialog 的创建
在上面的内容中,其实我们漏了很重要的一点,那就是 Dialog 的创建,也就是 onCreateDialog
方法:
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
Log.d(TAG, "onCreateDialog called for DialogFragment " + this);
}
return new Dialog(requireContext(), getTheme());
}
再往上追溯,其实就是到了 onGetLayoutInflater
中:
public LayoutInflater onGetLayoutInflater(@Nullable Bundle savedInstanceState) {
LayoutInflater layoutInflater = super.onGetLayoutInflater(savedInstanceState);
if (!mShowsDialog || mCreatingDialog) {
···
return layoutInflater;
}
prepareDialog(savedInstanceState);
···
if (mDialog != null) {
layoutInflater = layoutInflater.cloneInContext(mDialog.getContext());
}
return layoutInflater;
}
到这里我们就结束了,再往上,我们就要分析 Fragment 整套的布局流程了,我们只要知道,若想要自定义 DialogFragment 中的 Dialog,我们可以通过重载 onCreateDialog
的方式来解决这个问题。