农历2015年的最后一篇blog。
该篇为《Android 源码设计模式 解析与实践》Builder设计模式的读书笔记
Builder模式是什么?
Builder模式如同其名,其是一步一步创建一个复杂对象的创建型模式。该模式可以将一个复杂的对象与它的表示分离:做到同样的构建过程可以有不同的表示。
我们在什么场景下使用该模式:
当初始化一个对象特别复杂,参数多,且很多参数都具有默认值的时候,可以使用Builder模式。
Builder模式在日常Android开发当中,也是被我们经常用到,几乎每个Android程序员都用到过,只是自己不知道当前的代码已经蕴含了Builder模式在里面:
下面记录一段现在手中项目当中的一段代码:
PhotoGraph.Builder builder = new PhotoGraph.Builder(request.getContext());
builder.setEventTime(event.getTmGen())
.setLiftNumber(liftNo)
.setPriority(PhotoGraphConfig.LIFT_FAULT_PRIORITY)
.setZipFileName(zipFileName)
.setOnPhotoListener(new OnPhotoListener() {
@Override
public void openCameraFailure() {
//...
}
@Override
public void onCompletion(String filePath) {
//...
}
});
TaskPhotoGraph.getInstance().put(builder.create());
该代码片段就使用了Builder模式,下面在给出我们经常使用的AlertDialog代码:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("提示")
.setMessage("Message...")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// ....
}
}).setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// ...
}
});
builder.show();
ok,上面的代码片段就是我们经常要使用AlertDialog的实现,其实从类名就能看出是一个Builder模式,通过builder对象去组装AlertDialog的各个参数(如上面的Title、Message、PositiveButton、NegativeButton等),将AlertDialog的表示与构造进行了分离。
那既然知道了Builder模式是怎么个样子,下面就来分析分析Builder模式的实现,这里以AlertDialog的源码作为示例:
public class AlertDialog extends Dialog implements DialogInterface {
private AlertController mAlert; // mAlert 接受Builder成员变量p中各个参数
// ...省略一些代码
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
mAlert.setTitle(title);
}
public void setMessage(CharSequence message) {
mAlert.setMessage(message);
}
public static class Builder {
// 存储 AlertDialog的各个参数,用于创建AlertDialog的时候传递给AlertDialog的成员变量mAlert
private final AlertController.AlertParams P;
// ...省略一些代码
public Builder(Context context) {
this(context, resolveDialogTheme(context, 0));
}
// 设置各种参数
public Builder setTitle(int titleId) {
P.mTitle = P.mContext.getText(titleId);
return this;
}
public Builder setMessage(int messageId) {
P.mMessage = P.mContext.getText(messageId);
return this;
}
public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
P.mPositiveButtonText = text;
P.mPositiveButtonListener = listener;
return this;
}
public Builder setNegativeButton(CharSequence text, final OnClickListener listener) {
P.mNegativeButtonText = text;
P.mNegativeButtonListener = listener;
return this;
}
}
public AlertDialog create() {
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
// 将Builder中p的参数传递应用到AlertDialog中的mAlert对象中
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;
}
}
以上代码是从android.app.AlertDialog.java 类中截取的代码片。
从上述代码中,我们能知道的是:
- Builder类可以设置AlertDialog中需要用到的一切参数
- Builder 成员变量AlertController.AlertParams p用来存储AlertDialog待用的参数
- AlertDialog中的成员变量 mAlert对象中包含了与p一 一对应的成员变量
- Builder的create()方法中,会调用 p.apply(dialog.mAlert) 方法将p中早先设置的参数一 一传递到AlertDialog 的 mAlert 对象中
到这里为止,我们为Builder设置的一系列参数,已经全部由Builder 的成员变量AlertController.AlertParams p转移到了AlertDialog成员变量 mAlert对象中。这里我们不禁有一点疑惑了:
为什么传递这一系列参数要这么麻烦,要用到AlertController.AlertParam 和 AlertController 这两个对象去交接?为什么不在Builder类中一系列setXXX方法中将参数直接赋值给mAlert对应的成员变量
解释这一点很简单。这里可以仔细看看Builder类的声明为静态内部类,众所周知:java语法中静态类方法中无法引用非静态成员变量,也无法调用非静态方法。
而上面为什么可以使用AlertController.AlertParams p变量去存储设置给Builder的参数呢,答案很简单,因为在AlertController类中AlertParams类也是一个静态内部类。
以上就是Builder模式的一个具体实现。
现在接着往下看:AlertDialog现在只是拿到了这些参数(因为AlertDialog拥有AlertController 类型成员变量 mAlert ),后面在哪里使用到了这些参数呢?我们看看AlertDialog的show()方法
public AlertDialog show() {
AlertDialog dialog = create();
dialog.show();
return dialog;
}
AlertDialog的show()方法实际上又是调用了Dialog的show()方法(AlertDialog 继承 Dialog)
public void show() {
if (mShowing) { // 如果已经显示,直接return
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) {
// 1、调用onCreate()
dispatchOnCreate(null);
}
// 2、调用onStart()
onStart();
// 3、获取DecorView
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);
}
// 4、获取布局参数
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;
}
try {
// 5、将mDecor添加到WindowManager中
mWindowManager.addView(mDecor, l);
mShowing = true;
// 6、发送显示Dialog的消息
sendShowMessage();
} finally {
}
}
上面代码已经添加了注释,主要也就是做了注释中的6件事,从这6件事当中,我们能看到一些关于Dialog生命周期的方法,根据以往经验(回想下Activity的onCreate()方法中的setContentView(R.layout.activity_xxx_xxx);),一般在onCreate()方法中去构建AlertDialog视图内容。
上面注释1中调用了dispatchOnCreate()方法
void dispatchOnCreate(Bundle savedInstanceState) {
if (!mCreated) {
onCreate(savedInstanceState);
mCreated = true;
}
}
dispatchOnCreate()方法中又调用了onCreate()方法,onCreate()方法在Dialog中是一个空实现
protected void onCreate(Bundle savedInstanceState) {
}
上面已经说过AlertDialog继承Dialog那么具体实现应该在AlertDialog中
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAlert.installContent();
}
onCreate()方法中我们一眼看到,这里终于又回到了使用了mAlert对象(忘记了mAlert对象的,请回过头看下)
public void installContent() {
// 设置窗口没有title栏
mWindow.requestFeature(Window.FRATURE_NO_TITLE);
// 设置窗口视图布局
mWindow.setContentView(mAlertDialogLayout); //mAlertDialogLayout是默认的窗口视图布局对象
// 设置窗口的其它子视图内容
setupView();
}
这里调用mAlert的installContent()方法,在该方法中主要做了两件事:
调用Window对象的setContentView()方法(这里setContentView()同Activity的setContentView(),实际上Activity的setContentView()最终也是调用的Window对象setContentView())。因此这里就是设置AlertDialog布局的视图内容。
调用setupView(),为AlertDialog设置各项参数(即title、message 、icon、button等这些内容)
到此,我们在最开始使用Builder模式构建的一系列参数在setupView()方法中都得到了应用。
现在再回到之前AlertDialog的show()方法那里
if (!mCreated) {
// 1、调用onCreate()
dispatchOnCreate(null);
}
// ...省略一些代码
// 3、获取DecorView
mDecor = mWindow.getDecorView();
// ...省略一些代码
// 5、将mDecor添加到WindowManager中
mWindowManager.addView(mDecor, l);
mShowing = true;
// 6、发送显示Dialog的消息
sendShowMessage();
setupView()结束后,我们的视图内容填充完毕,视图布局也全部设置完成,并且关联到了Window对象,即mWindow拥有这个视图内容以及布局。到这里注释1的方法执行完毕,接着通过注释3、5、6的代码,显而易见:
WindowManager会将Window对象的DecorView
(即之前关联到Window对象的视图内容和视图布局)
添加到用户窗口上,并显示出来。用户也就看到了弹出来的AlertDialog。
以上就是对Builder设计模式的读书笔记。主要涉及到了:
- Builder设计模式的实现
- AlertDialog源码解析
同时如果弄清楚了AlertDialog源码,那么现在自定义自己的Dialog也是非常轻松的。
以上如有纰漏,不吝指出!
本文深入探讨了Builder设计模式的应用及其实现方式,并以AlertDialog为例详细解析了其源码,展示了如何利用Builder模式简化复杂对象的构建过程。

5726

被折叠的 条评论
为什么被折叠?



