Activity对Dialog的管理

来源:互联网 发布:java类加载的顺序 编辑:程序博客网 时间:2024/05/22 08:28

优点

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

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

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

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

实现

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

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

  1. 创建:要创建一个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;} 
  2. 调用:调用的时候只需要使用showDialog(int id)方法,这个传入的id自然就是前面定义好的id。

  3. 隐藏:想要dismiss的时候,可以用dialog自身的dismiss()方法,也可以用activity的dismissDialog(int id)方法。当dialog被dismiss之后,并没有被销毁,而是被activity保存了下来,下次调用的时候即可被复用
  4. 删除:如果不想被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消失的问题。

0 0