您的位置:首页 > 其它

Activity对Dialog的管理

2016-07-26 10:41 295 查看

优点

一般我们使用dialog时,都会在使用的时候创建一个新的dialog对象,然后显示出来,这样虽然很简单,但是当场景变得复杂时,就会出现问题:

比如当我们需要多次弹出一样的一个或几个弹窗,如果我们每次都创建一个新的对象,就会创造出很多对象,导致内存开销增大,这显然是我们不愿意看到的。

又或者当我们dialog正在显示时,activity意外销毁,比如用户切换横屏模式,导致activity销毁重建,这时候如果你只是简单的创建并显示了dialog,你的dialog就会消失了。

但是当你把dialog交给activity去管理,这些就都不再是问题。activity可以让你的dialog轻松复用,并且可以保存并恢复其状态。

实现

下面我们就来看一下如何实现:

既然是把dialog交给activity管理,就要让activity能够识别每个dialog。识别的方式就是给每个dialog加个编号,这个编号是int类型的。

创建:要创建一个dialog,需要在onCreateDialog()中实现创建dialog的语句。当然,不能忘了id。这里通常会采用switch语句,每一个id创建一个不同的dialog,像这样:

protected Dialog onCreateDialog(int id) {
Dialog dialog;
switch(id) {
case 0:
// do the work to define the 0 Dialog
break;
case 1:
// do the work to define the 1 Dialog
break;
default:
dialog = null;
}
return dialog;
}


调用:调用的时候只需要使用showDialog(int id)方法,这个传入的id自然就是前面定义好的id。

隐藏:想要dismiss的时候,可以用dialog自身的dismiss()方法,也可以用activity的dismissDialog(int id)方法。当dialog被dismiss之后,并没有被销毁,而是被activity保存了下来,下次调用的时候即可被复用

删除:如果不想被activity保存,则可以用removeDialog(int id)方法,删除某个dialog。

原理

以上就是使用的方法,非常简单,但是却好处多多,接下来就要看一下activity究竟背着我们干了些什么,让dialog的管理如此方便。

首先从调用的方法showDialog(id)说起:

public final void showDialog(int id) {
showDialog(id, null);
}

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去找,无疑dialog就是在这里保存的,这是一个SparseArray,所以我们的id需要是int型的。但是仔细一看就会发现mManagedDialogs里保存的并不是dialog,而是ManagedDialog,这里面不光有dialog,还有一个bundle,用来保存dialog的一些状态参数。

private static class ManagedDialog {
Dialog mDialog;
Bundle mArgs;
}


如果mManagedDialogs里没有,就去创建新的,这里我们自己实现的onCreateDialog()就派上用场了:

private Dialog createDialog(Integer dialogId, Bundle state, Bundle args) {
final Dialog dialog = onCreateDialog(dialogId, args);
if (dialog == null) {
return null;
}
//执行dialog的onCreate方法
dialog.dispatchOnCreate(state);
return dialog;
}


到这里,就获取到了dialog的实例,就可以在show里面展示了。同时activity还把它放到了mManagedDialogs中进行保存,这样就可以在下次调用同类型dialog的时候进行复用了。当然,保存对象的作用不只复用这么简单:

final void performSaveInstanceState(Bundle outState) {
onSaveInstanceState(outState);
saveManagedDialogs(outState);
mActivityTransitionState.saveState(outState);
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState);
}


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);
}


可以看到这是在activity保存状态的时候,会把mManagedDialogs中的所有dialog的状态都保存一遍,然后在恢复状态时就可以恢复到之前的状态:

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);
}
}
}
}


这样就解决了上面所说的类似于切换横屏后正在显示的dialog消失的问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息