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

     }

这段代码很简单,利用 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 管理的全部,以后应该能更灵活的使用对话框了吧

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值