Android源码学习之二-Activity如何管理对话框

我们都知道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();

    }

这段代码很简单,利用idmManagedDialogs数组中找到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);

                }

            }

        }

    }

到此,我们已经能够想到ActivityonDestory中如何销毁对话框了,没错,只要销毁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;

        }

        ……

    }

以上就是ActivityDialog管理的全部,以后应该能更灵活的使用对话框了吧

 

 

——欢迎转载,请注明出处,谢谢——

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

文斌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值