这两天看Android源码的时候,涉及到了比较常用的一个封装类:AlertDialog,众所周知这个Dialog封装了常用的Dialog使用的方法和样式,十分方便,也可以自定义很多想要的东西。这些不重要,里面比较精妙的我想就是那个Builder了,我们经常会在代码中这样优雅地构建一个AlertDialog。

    public void showDialog(){AlertDialog dialog = new AlertDialog.Builder(this).setTitle("Title").setMessage("Message").setPositiveButton("positive", null).setNegativeButton("negative", null).create();dialog.show();}

所以说命名规范重要呢,Builder很明显的暴露了,这是个建造者模式,先看下标准的建造者模式吧,比较晚了,我就百度找张图贴一下了。

网上有很多讲解AlertDialog源码的文章,我觉得对于初学者来说作用不大,因为源码里有很多细枝末节的东西,很容易让初学者分心而难以窥探到其本质。所以今天我换一个思路来说,仿照源码的思想来写一个同样调用方式的demo,把那些没用的细节都撇开,只看模式的思想是怎么运用的。好,先上代码。

package com.amuro.designPattern.builder.alert_dialog;import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.view.View;/*** Created by Amuro on 15/11/8.*/
public class MyAlertDialog extends Dialog implements DialogInterface
{private AlertController alertController;public MyAlertDialog(Context context){this(context, 0);}public MyAlertDialog(Context context, int themeResId){super(context, themeResId);alertController = new AlertController(context, this);}public static class Builder{private AlertParams params;public Builder(Context context){params = new AlertParams(context);}public Builder setTitle(String title){params.setTitle(title);return this;}public Builder setMessage(String message){params.setMessage(message);return this;}public Builder setLeftString(String leftString){params.setLeftString(leftString);return this;}public Builder setCenterString(String centerString){params.setCenterString(centerString);return this;}public Builder setRightString(String rightString){params.setRightString(rightString);return this;}public MyAlertDialog create(){MyAlertDialog dialog = new MyAlertDialog(params.getContext());params.apply(dialog.alertController);return dialog;}}
}

这个是我们自定义的AlertDialog,为了清晰我把里面所有的没用的代码全踢了,就只剩我们的Builder和AlertController了,这两个类也是AlertDialog原理的核心。Builder的产品是一个AlertParams,注意看每一个set方法都返回了一个Builder自己的指针,这也是我们的代码可以优雅的构建一个Dialog的基础,算是一个小技巧吧。在create方法中,我们会new一个自己的dialog,然后把dialog的成员AlertController传给了Params的apply方法(话说安卓源码里特别喜欢apply这个方法,不知是哪位大神的癖好)。下面来看AlertParams类。

package com.amuro.designPattern.builder.alert_dialog;import android.app.Dialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;import com.amuro.R;public class AlertParams
{private Context context;private String title;private String message;private String leftString;private String centerString;private String rightString;public AlertParams(Context context){this.context = context;}public void apply(AlertController alert){alert.init();if(title != null){alert.setTitle(title);}if(message != null){alert.setMessage(message);}if(leftString != null){alert.setLeftButtonText(leftString);}if(centerString != null){alert.setCenterButtonText(centerString);}if(rightString != null){alert.setRightButtonText(rightString);}}public Context getContext(){return context;}public void setContext(Context context){this.context = context;}public String getTitle(){return title;}public void setTitle(String title){this.title = title;}public String getMessage(){return message;}public void setMessage(String message){this.message = message;}public String getLeftString(){return leftString;}public void setLeftString(String leftString){this.leftString = leftString;}public String getCenterString(){return centerString;}public void setCenterString(String centerString){this.centerString = centerString;}public String getRightString(){return rightString;}public void setRightString(String rightString){this.rightString = rightString;}
}

get和set都不用看了,核心就是那个apply方法,那个方法里调用了AlertController的init方法完成了它的初始化,我们知道,我们show一个AlertDialog的时候并没有传入任何布局文件,那界面是从哪里来的呢?说到这里我想各位已经猜到了,没错,就是AlertController在做这件事,上代码。

package com.amuro.designPattern.builder.alert_dialog;import android.app.Dialog;
import android.content.Context;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.TextView;import com.amuro.R;public class AlertController
{private Context context;private Dialog dialog;private LayoutInflater layoutInflater;private View contentView;private TextView textViewTitle;private TextView textViewMessage;private Button buttonLeft;private Button buttonCenter;private Button buttonRight;public AlertController(Context context, Dialog dialog){this.context = context;this.dialog = dialog;}public void init(){dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);layoutInflater = LayoutInflater.from(context);contentView = layoutInflater.inflate(R.layout.my_alert_dialog, null);textViewTitle = (TextView)contentView.findViewById(R.id.tv_my_dialog_title);textViewMessage = (TextView)contentView.findViewById(R.id.tv_my_dialog_message);buttonLeft = (Button)contentView.findViewById(R.id.bt_my_dialog_left);buttonCenter = (Button)contentView.findViewById(R.id.bt_my_dialog_center);buttonRight = (Button)contentView.findViewById(R.id.bt_my_dialog_right);dialog.setContentView(contentView);}public void setTitle(String title){textViewTitle.setText(title);}public void setMessage(String message){textViewMessage.setText(message);}public void setLeftButtonText(String left){buttonLeft.setText(left);}public void setCenterButtonText(String center){if(!TextUtils.isEmpty(center)){buttonCenter.setVisibility(View.VISIBLE);buttonCenter.setText(center);}}public void setRightButtonText(String right){buttonRight.setText(right);}
}

看到这里是不是恍然大悟了,没错,就是AlertController完成了界面的初始化和构建工作,这里的demo很简单而实际上真正AlertController是非常复杂的。Android内置的AlertDialog对应的布局文件就是android.R.layoug.alert_dialog,而构建工作则对应于AlertController的installContent方法,具体的,请参考安卓源码,不再赘述。然后让我们看看我们自己的代码怎么运行吧。

public void showMyDialog(){MyAlertDialog dialog =new MyAlertDialog.Builder(this).setTitle("我的标题").setMessage("我的信息").setLeftString("取消").setCenterString("酱油").setRightString("确定").create();dialog.show();}

山寨度100%,perfect~可以看到,这个Builder模式并没有标准模版里面的Director类,因为大部分时候,Director其实是调用者本身,会有很多细节化的设置,用了Director反而限制了外部调用时的灵活性。所以,我们做事要基于理论,但也不能拘泥于理论,基于实际情况灵活掌握才是正道。通过这样的封装,成功的向外界隐藏了大量复杂的代码细节,让调用者可以轻松优雅的实现想要的功能。我想,这应该是每一个优秀的程序员在实现功能后对自己的要求吧。最后上一下效果图吧。

通过Demo了解AlertDialog的构造原理相关推荐

  1. 计算机用的机械硬盘的工作原理,为啥一震就坏?机械硬盘的构造原理是什么?...

    最近本人的一块2TB机械硬盘挂掉了,里面有工作五六年的重要数据,以及一些生活当中比较重要的照片被销存了.其实这块硬盘之前没有任何的异样,用鲁大师查询硬盘的时候,也没有出现任何警告等消息,仔细回想,有可 ...

  2. 激光测距仪构造原理及激光安全说明——TFN BKD系列双目军绿激光测距测高仪

    一.概述 手持激光测距仪是集现代电子.光学.激光技术准确测量距离的新一代军用望远镜式测距仪,具有体积小.重量轻.测程远.操作简便.测距误差小.密封性能好.可靠性高等特点,适用于军事观测,航道.河床.邮 ...

  3. 形函数的构造原理-有限元形函数的几个种类

    在有限元法中,形函数是一个十分重要的概念.它不仅可以用做单元的内插函数,把单元内任一点的位移用节点位移表示,而且可作为加权余量法中的加权函数,可以处理外载荷,将分布力等效为节点上的集中力和力矩,此外, ...

  4. 构造原理中的独立性条件如果不满足,是否原结论仍然成立?试用模拟的方法验证你的结论。

    以下博客解决: 构造原理中的独立性条件如果不满足,是否原结论仍然成立?试用模拟的方法验证你的结论. 构造原理中的独立性条件如果不满足,则原结论不成立. X 1 X_{1} X1​

  5. 详解三大抽样分布的构造原理,以及随机数的产生

    抽样分布定理及随机数的产生 1 四种常用统计分布及构造原理 1.1 标准正态分布 1.2 χ 2 \chi^{2} χ2

  6. 铣扁机的常用加工方法及构造原理

    铣扁机是两个面对称的铣扁,通常所指的就是轴类产品的扁位对称切削位置.铣扁机的常用加工方法以及构造原理是怎样的呢? 铣扁机的加工方法有三种,一是小卧铣,二是铣床,三是铣扁机. 小窝铣是一些精度不高的轴类 ...

  7. 弹簧导电针是怎样一个构造原理与怎么应用呢?

    弹簧导电针看起来十分普通,不起眼.但是它的功能却十强大,应用范围也十分广泛.小到手机.手表,大到飞机.汽车,我们都能看到它的身影.那么弹簧导电针是怎样一个构造原理呢?它又有哪些应用呢?今天景诚实业小编 ...

  8. 电子电路基础 (10)——场效应管的构造原理及使用

    一.场效应管的构造以及认识(非常重要) 两只半引脚的,上面的是散热,和中间的半只引脚连在一起的. 1.1 场效应管的构造 场效应管简称FET,与三极管一样也分三个极:其中D极称为漏极(也称为供电极), ...

  9. 理解立刻执行函数(IIFE)的构造原理、运行机制

    立刻执行函数(Imdiately Invoked Function Expression)到底是什么意思呢? 顾名思义:在该函数定义之后立即被执行的函数. 许多小伙伴应该和我有同样的想法:这不很好操作 ...

最新文章

  1. 比PCA更好用的监督排序—LDA分析、作图及添加置信-ggord
  2. mysql导入导出数据库
  3. 单例设计模式singleton
  4. Xamarin.Forms的相对布局RelativeLayout
  5. 程序员带娃有多“恐怖” ?!
  6. 如何在 CentOS 上启用 软件集 Software Collections(SCL)
  7. oracle:小知识点
  8. 四阶龙格库塔c语言,四阶龙格库塔算法的C语言实现
  9. JMETER从JSON响应中提取数据
  10. 2017-2018-1 20179215《Linux内核原理与分析》第二周作业
  11. 【区块链】以太坊truffle+web3+ganache简单实践
  12. Selenium私房菜系列6 -- 深入了解Selenium RC工作原理(1)
  13. 绝地求生 java 雷达透视_绝地求生jar雷达透视辅助
  14. c#语言猜数字游戏,C#实现猜数字小游戏
  15. 有关Excel表格公式的方式进行前边数字排序,后边内容不变的方法。
  16. macd底背离的python_java尝试编写macd,试验顶背离底背离
  17. 推荐基于4G模块打造的超低功耗4G摄像头通讯板
  18. 【编程珠玑】陪着奶猫看看书--《编程珠玑》第一章
  19. 中科院计算机和理论物理双硕士白,[中科院物理研究所]2005年硕士招生专业及研究方向_跨考网...
  20. 码分多址CDMA及计算(简单易懂)

热门文章

  1. CSDN博客编辑格式
  2. js echarts 水球图
  3. java编程捕鱼和分鱼_C_捕鱼和分鱼
  4. js(jquery方式) 直接访问 elasticsearch
  5. Python笔记----使用raise引发异常
  6. SAS9.4 修改sashost.dll系统时间
  7. 欧洲中世纪末期的战争
  8. S-属性定义与L-属性定义
  9. 使用C语言+USRP B210从零开始实现无线通信(2) 获取以太网数据并封装
  10. 推荐个WIN7下小巧的可转录声音的软件-Audio Record Wizard V6.99