我们都知道
Activity
负责生成、保存、恢复对话框,下面我们就来了解一下
Activity
的对话框管理机制。
在
Activity
的源码中我们可以看到
private static class ManagedDialog {
Dialog mDialog;
Bundle mArgs;
}
private SparseArray<ManagedDialog> mManagedDialogs;
私有类
ManagedDialog
通过封装一个
Dialog
和一个
Bundle
保存对话框的引用及相关参数,另外使用一个
SparseArray<ManagedDialog>
数组,来保存了
Activity
生成的每一个对话框的信息。
SparseArray
是一个升序排列的有序数组,采用
Key+Value
的方式形成类似于字典的数据结构,通过
Key
即可操作
Value
,其中
Key
是一个
Int
类型,
Value
是一个
Object
类型。该数组的内部搜索采用了二分查找算法,因此搜索速度很快。
下面我们来看一下显示对话框时的
Activity
中的处理机制。
public final boolean showDialog(int id, Bundle args) {
if (mManagedDialogs == null) {
mManagedDialogs = new SparseArray<ManagedDialog>();
}
ManagedDialog md = mManagedDialogs.get(id);
if (md == null) {
md = new ManagedDialog();
md.mDialog = createDialog(id, null, args);
if (md.mDialog == null) {
return false;
}
mManagedDialogs.put(id, md);
}
md.mArgs = args;
onPrepareDialog(id, md.mDialog, args);
md.mDialog.show();
return true;
}
从上面的代码不难看出,通过在
mManagedDialogs
数组中查找,可以判断指定
id
的对话框是否已经生成,如果没有生成,就新建一个
ManagedDialog
对象,为其
mDialog
创建一个对话框
createDialog()
,并将该
ManagedDialog
对象存入
mManagedDialogs
数组中;否则则直接调用
onPrepareDialog()
函数,能过
show()
将对话框显示出来。
这里值得一提的是
createDialog()
函数,其实现代码如下:
private Dialog createDialog(Integer dialogId, Bundle state, Bundle args) {
final Dialog dialog = onCreateDialog(dialogId, args);
if (dialog == null) {
return null;
}
dialog.dispatchOnCreate(state);
return dialog;
}
在该函数的第一行就回调了
onCreateDialog()
函数。
结合前面的代码可以发现,
onCreateDialog()
与
onPrepareDialog()
函数为我们提供了对对话框额外的处理能力,在我们自己的派生
Activity
中可以通过重写这两个函数来做一些特殊处理,但是需要注意的是,
onCreateDialog()
函数中在一个
ID
标识的对话框第一次创建的时候才会被回调,如果该对话框已经创建过,即使没有显示,由于存在于
mManagedDialogs
数组中,所以是不会再次触发
onCreateDialog()
函数的,但
onPrepareDialog()
函数是不受此限制的。
同样我们再来看一下隐藏对话框的代码。
public final void dismissDialog(int id) {
if (mManagedDialogs == null) {
throw missingDialog(id);
}
final ManagedDialog md = mManagedDialogs.get(id);
if (md == null) {
throw missingDialog(id);
}
md.mDialog.dismiss();
}
这段代码很简单,利用
id
在
mManagedDialogs
数组中找到
ManagedDialog
并调用其
mDialog.dismiss()
即可。
移除对话框也可以想见,只是从
mManagedDialogs
数组中
remove()
掉即可。
public final void removeDialog(int id) {
if (mManagedDialogs == null) {
return;
}
final ManagedDialog md = mManagedDialogs.get(id);
if (md == null) {
return;
}
md.mDialog.dismiss();
mManagedDialogs.remove(id);
}
我们知道
Activity
的生命周期,当
Activity
在前后台切换的时候,涉及到保存和恢复状态,这其中当然也要对对话框的状态进行处理,我们先来看一下当
Activity
切到后台时的状态保存处理。
private void saveManagedDialogs(Bundle outState) {
if (mManagedDialogs == null) {
return;
}
final int numDialogs = mManagedDialogs.size();
if (numDialogs == 0) {
return;
}
Bundle dialogState = new Bundle();
int[] ids = new int[mManagedDialogs.size()];
// save each dialog's bundle, gather the ids
for (int i = 0; i < numDialogs; i++) {
final int key = mManagedDialogs.keyAt(i);
ids[i] = key;
final ManagedDialog md = mManagedDialogs.valueAt(i);
dialogState.putBundle(savedDialogKeyFor(key), md.mDialog.onSaveInstanceState());
if (md.mArgs != null) {
dialogState.putBundle(savedDialogArgsKeyFor(key), md.mArgs);
}
}
dialogState.putIntArray(SAVED_DIALOG_IDS_KEY, ids);
outState.putBundle(SAVED_DIALOGS_TAG, dialogState);
}
整个的对话框信息保存用的是
dialogState
这个
Bundle
对象,遍历
mManagedDialogs
数组,对其中的每一个对话框信息,把对话框自身的
onSaveInstanceState()
返回的
Bundle
加入到
dialogState
中,再把对话框信息中保存的对话框参数存入
dialogState
中。最后将所有的对话框
id
形成的
int
数组再存入
dialogState
中,对话框的保存即告完成。
同理,恢复对话框是保存的逆过程,源码如下:
private void restoreManagedDialogs(Bundle savedInstanceState) {
final Bundle b = savedInstanceState.getBundle(SAVED_DIALOGS_TAG);
if (b == null) {
return;
}
final int[] ids = b.getIntArray(SAVED_DIALOG_IDS_KEY);
final int numDialogs = ids.length;
mManagedDialogs = new SparseArray<ManagedDialog>(numDialogs);
for (int i = 0; i < numDialogs; i++) {
final Integer dialogId = ids[i];
Bundle dialogState = b.getBundle(savedDialogKeyFor(dialogId));
if (dialogState != null) {
// Calling onRestoreInstanceState() below will invoke dispatchOnCreate
// so tell createDialog() not to do it, otherwise we get an exception
final ManagedDialog md = new ManagedDialog();
md.mArgs = b.getBundle(savedDialogArgsKeyFor(dialogId));
md.mDialog = createDialog(dialogId, dialogState, md.mArgs);
if (md.mDialog != null) {
mManagedDialogs.put(dialogId, md);
onPrepareDialog(dialogId, md.mDialog, md.mArgs);
md.mDialog.onRestoreInstanceState(dialogState);
}
}
}
}
到此,我们已经能够想到
Activity
在
onDestory
中如何销毁对话框了,没错,只要销毁
mManagedDialogs
数组就行了。
protected void onDestroy() {
// dismiss any dialogs we are managing.
if (mManagedDialogs != null) {
final int numDialogs = mManagedDialogs.size();
for (int i = 0; i < numDialogs; i++) {
final ManagedDialog md = mManagedDialogs.valueAt(i);
if (md.mDialog.isShowing()) {
md.mDialog.dismiss();
}
}
mManagedDialogs = null;
}
……
}
以上就是
Activity
对
Dialog
管理的全部,以后应该能更灵活的使用对话框了吧
Android源码学习之二-Activity如何管理对话框
最新推荐文章于 2025-12-31 19:19:25 发布
本文详细解析了Android Activity 对话框管理的全过程,包括对话框的创建、显示、隐藏、移除以及对话框状态的保存和恢复。通过源码分析,展示了如何灵活使用对话框功能。
766

被折叠的 条评论
为什么被折叠?



