集美阅读大全是一个以文章句子为主题的在线阅读网站。内含有各种经典好文章,爱情美文,诗歌散文,情感句子说说,范文资料等。读好文章,尽在集美阅读大全!!!
当前位置:集美阅读大全 >杂文 > 正文

AlertDialog中的Builder模式

2019-09-18 16:46AlertDialog Builder 模式

image.png

序言

AlertDialog是安卓系统中常用的对话框,它采用Builder设计模式,将对话框的创建和表现显示分离。下面我就来分析一下AlertDialog的源码。

跟踪源码

首先看一下AlertDialog的定义:

public class AlertDialog extends Dialog implements DialogInterface {     private AlertController mAlert;     //其他代码省略 } 

AlertDialog继承Dialog,实现DialogInterface接口。并且有一个成员变量mAlert : AlertController,我们待会来分析mAlert的作用。
AlertDialog的用法如下:

private void showDialog(Context context) {     AlertDialog.Builder builder = new AlertDialogBuilder(context);     builder.setIcon(R.drawable.icon);     builder.setTitle("标题");     builder.setMessage("这是对话框显示的内容");     builder.setPositiveButton("确定", null);     builder.setNegativeButton("取消", null);     builder.create().show(); //构建AlertDialog并显示 } 

AlertDialog都是通过Builder来构建的,我们看一下Builder的代码:

public static class Builder {     private final AlertController.AlertParams P;      public Builder(Context context) {         this(context, resolveDialogTheme(context, ResourceId.ID_NULL));     }      public Builder(Context context, int themeResId) {         P = new AlertController.AlertParams(new ContextThemeWrapper(                 context, resolveDialogTheme(context, themeResId)));     }      /**      * Set the title using the given resource id.      *      * @return This Builder object to allow for chaining of calls to set methods      */     public Builder setTitle(@StringRes int titleId) {         P.mTitle = P.mContext.getText(titleId);         return this;     }      //一些列setXXX方法,用来设置对话框需要的各种参数          public AlertDialog create() {         // Context has already been wrapped with the appropriate theme.         final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);         P.apply(dialog.mAlert);         dialog.setCancelable(P.mCancelable);         if (P.mCancelable) {             dialog.setCanceledOnTouchOutside(true);         }         dialog.setOnCancelListener(P.mOnCancelListener);         dialog.setOnDismissListener(P.mOnDismissListener);         if (P.mOnKeyListener != null) {             dialog.setOnKeyListener(P.mOnKeyListener);         }         return dialog;     }          public AlertDialog show() {         final AlertDialog dialog = create();         dialog.show();         return dialog;     } 

Builer有一个成员变量P : AlertController.AlertParams,通过setXXX设置的参数最终保存在P中,调用create()创建对话框时,又调用了P.allply(dialog.mAlert)方法:

public void apply(AlertController dialog) {     if (mCustomTitleView != null) {         dialog.setCustomTitle(mCustomTitleView);     } else {         if (mTitle != null) {             dialog.setTitle(mTitle);         }         if (mIcon != null) {             dialog.setIcon(mIcon);         }         if (mIconId != 0) {             dialog.setIcon(mIconId);         }         //设置各种属性         ...... } 

可以看到,apply的作用是把AlertController.Params保存的对话框参数设置给AlertController。
Builder.create方法调用之后,创建了AlertDialog对象,接下来调用Builder.show方法展示对话框:

public AlertDialog show() {     final AlertDialog dialog = create();     dialog.show();     return dialog; } 

转而调用Dialog.show方法:

public void show() {     if (mShowing) {         if (mDecor != null) {             if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {                 mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);             }             mDecor.setVisibility(View.VISIBLE);         }         return;     }      mCanceled = false;      if (!mCreated) {         dispatchOnCreate(null);     } else {         // Fill the DecorView in on any configuration changes that         // may have occured while it was removed from the WindowManager.         final Configuration config = mContext.getResources().getConfiguration();         mWindow.getDecorView().dispatchConfigurationChanged(config);     }      onStart();     mDecor = mWindow.getDecorView();      if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {         final ApplicationInfo info = mContext.getApplicationInfo();         mWindow.setDefaultIcon(info.icon);         mWindow.setDefaultLogo(info.logo);         mActionBar = new WindowDecorActionBar(this);     }      WindowManager.LayoutParams l = mWindow.getAttributes();     if ((l.softInputMode             & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {         WindowManager.LayoutParams nl = new WindowManager.LayoutParams();         nl.copyFrom(l);         nl.softInputMode |=                 WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;         l = nl;     }      mWindowManager.addView(mDecor, l);     mShowing = true;      sendShowMessage(); } 

可以看到,Dialog.show方法中做了以下几件事:

  1. 通过dispatchOnCreate调用AlertDialog.onCreate方法
  2. 调用AlertDialog的onStart方法
  3. 将Dialog的DecorView添加到WindowManager中

很明显,这就是一系列典型的生命周期方法,按照惯例,AlertDialog的内容构建应该在onCreate方法中,我们验证一下:

@Override protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     mAlert.installContent(); } 

AlertDialog.onCreate调用mAlert : AlertController.installContent方法:

public void installContent() {     int contentView = selectContentView();     mWindow.setContentView(contentView);     setupView(); } 

该方法很简短,其中有一句代码很显眼mWindow.setContentView(contentView),我们都知道,Activity.setContentView实际就是调用Window.setContentView,可见,Dialog和Activity设置视图的方式相同。
setContentView方法接收layoutId,即contentView是布局id:

private int selectContentView() {     if (mButtonPanelSideLayout == 0) {         return mAlertDialogLayout;     }     if (mButtonPanelLayoutHint == AlertDialog.LAYOUT_HINT_SIDE) {         return mButtonPanelSideLayout;     }     // TODO: use layout hint side for long messages/lists     return mAlertDialogLayout; } 

这里有两种布局,一种是带Button,一种不带Button,它们在AlertController的构造方法中初始化:

protected AlertController(Context context, DialogInterface di, Window window) {     mContext = context;     mDialogInterface = di;     mWindow = window;     mHandler = new ButtonHandler(di);      final TypedArray a = context.obtainStyledAttributes(null,             R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);      mAlertDialogLayout = a.getResourceId(             R.styleable.AlertDialog_layout, R.layout.alert_dialog);     mButtonPanelSideLayout = a.getResourceId(             R.styleable.AlertDialog_buttonPanelSideLayout, 0);     mListLayout = a.getResourceId(             R.styleable.AlertDialog_listLayout, R.layout.select_dialog);      mMultiChoiceItemLayout = a.getResourceId(             R.styleable.AlertDialog_multiChoiceItemLayout,             R.layout.select_dialog_multichoice);     mSingleChoiceItemLayout = a.getResourceId(             R.styleable.AlertDialog_singleChoiceItemLayout,             R.layout.select_dialog_singlechoice);     mListItemLayout = a.getResourceId(             R.styleable.AlertDialog_listItemLayout,             R.layout.select_dialog_item);     mShowTitle = a.getBoolean(R.styleable.AlertDialog_showTitle, true);      a.recycle();      /* We use a custom title so never request a window title */     window.requestFeature(Window.FEATURE_NO_TITLE); } 

AlertDialog中的布局资源就是alert_dialog.xml这个文件,由于该布局文件内容较长,我们就用一张图描述一下它的结构:

image.png

分析了setContentView之后,我们看一下setupView方法:

private void setupView() {     final View parentPanel = mWindow.findViewById(R.id.parentPanel);     final View defaultTopPanel = parentPanel.findViewById(R.id.topPanel);     final View defaultContentPanel = parentPanel.findViewById(R.id.contentPanel);     final View defaultButtonPanel = parentPanel.findViewById(R.id.buttonPanel);      // Install custom content before setting up the title or buttons so     // that we can handle panel overrides.     final ViewGroup customPanel = (ViewGroup) parentPanel.findViewById(R.id.customPanel);     setupCustomContent(customPanel);      final View customTopPanel = customPanel.findViewById(R.id.topPanel);     final View customContentPanel = customPanel.findViewById(R.id.contentPanel);     final View customButtonPanel = customPanel.findViewById(R.id.buttonPanel);      // Resolve the correct panels and remove the defaults, if needed.     final ViewGroup topPanel = resolvePanel(customTopPanel, defaultTopPanel);     final ViewGroup contentPanel = resolvePanel(customContentPanel, defaultContentPanel);     final ViewGroup buttonPanel = resolvePanel(customButtonPanel, defaultButtonPanel);      setupContent(contentPanel);     setupButtons(buttonPanel);     setupTitle(topPanel);     //省略其他内容     ...... } 

可以看到,代码中的setupContent、setupButtons、setupTitle就是真正初始化对话框视图。其中还有一个setupCustomContent方法,该方法是初始化自定义的View,即通过setView设置:

/**  * Set the view resource to display in the dialog.   */  public void setView(int layoutResId) {      mView = null;      mViewLayoutResId = layoutResId;      mViewSpacingSpecified = false;  } 

如果不设置自定义view,customPanel就不可见。

上面介绍了对话框的创建和初始化过程,那么怎么显示对话框呢?
在Builder.show方法中有一句:

sendShowMessage(); 

通过sendShowMessage发送一个显示对话框的消息。

总结

AlertDialog采用了Builder设计模式,把对话框的构建和表示分离开来,使得同样的构建过程可以创建不同的表示。
AlertDialog的构建是在Builder.create方法,而视图初始化和显示则是在Builder.show方法中。
使用自定义AlertDialog时需要注意一点:只有调用Builder.show方法之后,才能获取布局中的View进行初始化

您可能感兴趣的文章

  • AlertDialog源码解析
  • AlertDialog入门与详解(多种实现示例:自定义布局等)
  • Android进阶:七、Retrofit2.0原理解析之最简流程【上】
  • Android网络连接判断与处理
  • 链表反转,照抄都失败,我到底错哪里了?求助大牛
  • Android实现多线程下载文件,支持断点
  • RocketMQ中Broker的消息存储源码分析
  • 单例模式的理解和示例

未经允许不得转载:杂烩网 » AlertDialog中的Builder模式

课后答案张九龄《望月怀远》阅读答案及全诗翻译赏析

望月怀远张九龄海上生明月,天涯共此时。情人怨遥夜,竟夕起相思。灭烛怜光满,披衣觉露滋。不堪盈手赠,还寝梦佳期。注释⑴怀远:怀念远方的亲人。⑵最前面两句:辽阔无边的大海上升起一轮明月,使人想起了远在天涯……
2023-11-22 04:53暂无评论阅读详情

课后答案王安石《次韵唐公三首其三旅思》阅读答案

次韵唐公三首其三旅思王安石此身南北老,愁见问征途。地大蟠三楚,天低入五湖。看云心共远,步月影同孤。慷慨秋风起,悲歌不为鲈②。注:①张壤,字唐公,北宋嘉佑六年契丹国母生辰使,王安石友人。②《晋书&mid……
2023-11-22 04:52暂无评论阅读详情

笔记心得各级干部学习执法为民心得体会

  “各级干部都要牢固树立全心全意为人民服务的思想和真心实意对人民负责的精神,做到心里装着群众,凡事想着群众,工作依靠群众,一切为了群众。要坚持权为民所用,情为民所系,利为民所谋,为群众诚……
2023-11-22 04:12暂无评论阅读详情

笔记心得寒假大学生社会实践心得体会

  自从走进了大学,就业问题就似乎总是围绕在我们的身边,成了说不完的话题。在现今社会,招聘会上的大字报都总写着“有经验者优先”,可还在校园里面的我们这班学子社会经验又会拥有多少……
2023-11-22 04:08暂无评论阅读详情

协议书济南市某美容院转让协议第2篇

  __________美容院根据中华人民共和国国务院劳动法规和________市私营企业劳动管理实施办法,结合本美容院经营的具体所需今制订此劳动合同书。  双……
2023-11-22 02:36暂无评论阅读详情

剧本劳模宣传短剧剧本《阿咪也想当劳模》

  1、机械厂门卫处,日,外。  清早,机械厂班长李玉伟开着别克赛欧小汽车驶进厂区,门卫室内的保安一边按开电动门,一边朝李玉伟摆手。  李玉伟:(摇下车窗,笑着打招呼)小秦,早。  保安小秦:(笑着)……
2023-11-22 02:11暂无评论阅读详情

教程灰雀说课稿

灰雀说课稿  灰雀说课稿(一):  《灰雀》说课稿  一、说教材  《灰雀》是义务教育课程标准实验教科书,小学语文第五册第二单元的一篇讲读课文。这篇课文记叙了列宁在莫斯科郊外养病期间爱护灰雀的故事。列……
2023-11-22 00:41暂无评论阅读详情

课件“吴隐之字处默,濮阳鄄城人”阅读答案及原文

吴隐之字处默,濮阳鄄城人。美姿容,善谈论,博涉文史,以儒雅标名。弱冠而介立,有清操,虽儋石无储,不取非其道。事母孝谨,及其执丧,哀毁过礼。与太常韩康伯邻居,康伯母,贤明妇人也,每闻隐之哭声,辍餐投箸,……
2023-11-22 00:38暂无评论阅读详情

标签