建造者模式
一. 概念及其生活案例
生活案例:顾名思义,重点就是建造的过程。举例:造车,车是由各种各样的零件组装而成,底盘,轮胎,外壳,座椅等等,生成的流程还是非常固定的,可以把这些组成部分看成一系列的复杂的对象,轮胎可能需要各样的材料组成,外壳或许会有颜色的定制或者材料质量要求,座椅也许也会定制要求真皮材质,非常的多元化。但是它们的组装流程是一样不变的,变化的是它们这些配件的一些内部的细节(颜色,材质等等),但是不影响我们组装汽车的流程。
定义:
指一个复杂对象的构造和它的表示分离,使得同样的构建流程可以创建不同的表示,被称为建造者模式,它是将一个复杂的对象分解为多个简单的对象,然后一步步构建而成,它将变与不变相分离,即产品的组成部分是不变的,但是产品的每一个部分是可以灵活选择的。
代码示例
第一步:确定一个产品对象,它是由若干个简单对象部分A,B,C组成,我们看到A,B,C三个简单对象我们都提供了set方法去设置它,但其实根据具体需求product并不是三个对象都需要,所以这是不固定的set方法。什么意思呢,比如我们外部调用这个Product对象的时候,可能会有选择性的去setA,setB,setC。可控性就会比较强,当我们需要什么再去调用什么。
/**
* 产品 是复杂对象
*/
public class Product {
private PartA partA;
private PartB partB;
private PartC partC;
public PartA getPartA() {
return partA;
}
public void setPartA(PartA partA) {
this.partA = partA;
}
public PartB getPartB() {
return partB;
}
public void setPartB(PartB partB) {
this.partB = partB;
}
public PartC getPartC() {
return partC;
}
public void setPartC(PartC partC) {
this.partC = partC;
}
public void show() {
Log.e("product", "show: A" + partA.getName());
Log.e("product", "show: B" + partB.getName());
Log.e("product", "show: C" + partC.getName());
}
}
public class PartA {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class PartB {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class PartC {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
产品类定义好之后,我们就可以抽象一个Builder类,来执行我们的构建流程。一个复杂对象的流程是始终不变的,变化的是它的成分而已,所以我们可以使用抽象类作为基类。所有的内容都会在我们的build()函数里面进行构建。
abstract public class Builder {
Product product;
public abstract void setPartA(String nameA);
public abstract void setPartB(String nameB);
public abstract void setPartC(String nameC);
public abstract void build();
public Product getProduct() {
return product;
}
}
//这个是Builder的实现类,我们这里主要看Build方法,模拟建造者的过程
//build方法把三个A,B,C简单对象都实例化了出来,并且组装到product复杂对象上,这就是建造的核心
public class ConcreateBuilder extends Builder {
private String nameA;
private String nameB;
private String nameC;
@Override
public void setPartA(String nameA) {
this.nameA = nameA;
}
@Override
public void setPartB(String nameB) {
this.nameB = nameB;
}
@Override
public void setPartC(String nameC) {
this.nameC = nameC;
}
@Override
public void build() {
PartA partA = new PartA();
if (!TextUtils.isEmpty(nameA)) {
partA.setName(nameA);
}
PartB partB = new PartB();
if (!TextUtils.isEmpty(nameB)) {
partB.setName(nameB);
}
PartC partC = new PartC();
if (!TextUtils.isEmpty(nameC)) {
partC.setName(nameC);
}
product = new Product();
product.setPartA(partA);
product.setPartB(partB);
product.setPartC(partC);
}
}
第三方调用
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//这里实例化了抽象类Builder的实现类对象,并且对product里面的简单对象A,B,C赋值
Builder builder = new ConcreateBuilder();
//这里我们可以看到,我们可以选择性的对A,B,C赋值,根据实际情况而定,即便没有赋值就是默认值。
//毫不影响Product这个复杂对象的创建,只是Product里面的参数ABC三个值不一样罢了,这就是参数可变性,建造过程不变性。
builder.setPartA("111");
builder.setPartB("22222");
builder.setPartC("333");
builder.build();
Product product = builder.getProduct();
product.show();
}
}
增强版标题栏代码实例
先看下面的图,我们app常见的标题栏就会用到建造者模式了,因为我们的标题栏可能会多种多样,我们要把握住变化的部分,也就是标题栏上面的内容,不变的部分就是标题栏本身,所以标题栏就是一个复杂的对象,标题栏上面可以有不同的内容,这些不同的内容就是组成复杂对象的简单对象。
接下来我们看代码模拟这个过程,我们一般是面向接口编程最优,我们首先明确好我们构建过程需要做些什么,在接口里面定义好对应的抽象方法,明确了需要做什么之后我们再写实现类去实现对应的功能。下面是自定义的一个Navigation的接口。
/**
* 构建过程
*/
public interface INavigation {
/**
* 创建一个NavigationBar
*/
void createNavigationBar();
/**
* 绑定一些参数 控件,以及控件上的信息等等,参数可选可不选
*/
void attachNavigationParams();
/**将navigation绑定到父控件
* @param navigationView
* @param parent
*/
void attachParent(View navigationView, ViewGroup parent);
}
然后我们新建一个AbsNavigationBar的Builder内部类,主要是为了统一管理一些东西,抽取出公共的内容。在这个Builder类里面我们写了setText和setOnClickListener两个自定义方法,为的就是调用的时候统一的创建。
//这是基类抽象类
public class AbsNavigationBar<T extends AbsNavigationBar.Builder> implements INavigation {
private T mBuilder;
private View mNavigationView;
protected AbsNavigationBar(T mBuilder) {
this.mBuilder = mBuilder;
createNavigationBar();
}
@Override
public void createNavigationBar() {
mNavigationView = LayoutInflater.from(mBuilder.mContext).inflate(mBuilder.mLayoutId, mBuilder.mParent, false);
//添加
attachParent(mNavigationView, mBuilder.mParent);
//绑定文本和点击事件
attachNavigationParams();
}
@Override
public void attachNavigationParams() {
/**
* 文本
*/
Map<Integer, String> textMap = mBuilder.textMap;
for (Map.Entry<Integer, String> entry : textMap.entrySet()) {
//绑定文本内容
TextView textView = findViewBind(entry.getKey());
textView.setText(entry.getValue());
}
/**
* 点击事件
*/
Map<Integer, View.OnClickListener> clickListenerMap = mBuilder.clickListenerMap;
for (Map.Entry<Integer, View.OnClickListener> entry : clickListenerMap.entrySet()) {
View view = findViewBind(entry.getKey());
view.setOnClickListener(entry.getValue());
}
}
public <T extends View> T findViewBind(int id) {
return mNavigationView.findViewById(id);
}
@Override
public void attachParent(View navigationView, ViewGroup parent) {
parent.addView(navigationView, 0);
}
public static abstract class Builder<T extends Builder> {
public Context mContext;
public int mLayoutId;
//存储对应id和文本容器
public Map<Integer, String> textMap;
//存储对应id和点击事件的容器
public Map<Integer, View.OnClickListener> clickListenerMap;
public ViewGroup mParent;
//子类继承该抽象类的时候会通过构造函数对这些参数赋值
public Builder(Context context, int layoutId) {
Activity activity = (Activity) context;
ViewGroup viewGroup = (ViewGroup) activity.getWindow().getDecorView();
this.mParent = (ViewGroup) viewGroup.getChildAt(0);
this.mContext = context;
this.mLayoutId = layoutId;
textMap = new HashMap<>();
clickListenerMap = new HashMap<>();
}
//设置文字
public T setText(int textId, String textString) {
textMap.put(textId, textString);
return (T) this;
}
//设置点击事件
public T setOnClickListener(int viewId, View.OnClickListener listener) {
clickListenerMap.put(viewId, listener);
return (T) this;
}
//创建标题栏对象
public abstract AbsNavigationBar create();
}
}
/**
主要是用来接受一些参数,比如控件上的一些文字信息,或者对应控件的点击事件,假设我们一个个去写在每个页面
会导致代码很臃肿,所以这里用这个类统一管理。
*/
public static abstract class Builder<T extends Builder> {
public Context mContext;
public int mLayoutId;
//存储对应id和文本容器
public Map<Integer, String> textMap;
//存储对应id和点击事件的容器
public Map<Integer, View.OnClickListener> clickListenerMap;
public ViewGroup mParent;
public Builder(Context context, int layoutId) {
Activity activity = (Activity) context;
ViewGroup viewGroup = (ViewGroup) activity.getWindow().getDecorView();
this.mParent = (ViewGroup) viewGroup.getChildAt(0);
this.mContext = context;
this.mLayoutId = layoutId;
textMap = new HashMap<>();
clickListenerMap = new HashMap<>();
}
//设置文字
public T setText(int textId, String textString) {
textMap.put(textId, textString);
return (T) this;
}
//设置点击事件
public T setOnClickListener(int viewId, View.OnClickListener listener) {
clickListenerMap.put(viewId, listener);
return (T) this;
}
public abstract AbsNavigationBar create();
}
}
//具体实现类
public class DefaultNavigationBar extends AbsNavigationBar<AbsNavigationBar.Builder> {
protected DefaultNavigationBar(AbsNavigationBar.Builder mBuilder) {
super(mBuilder);
}
public static class Builder extends AbsNavigationBar.Builder<AbsNavigationBar.Builder> {
public Builder(Context context) {
super(context, R.layout.navigation_layout);
}
@Override
public DefaultNavigationBar create() {
return new DefaultNavigationBar(this);
}
//返回this是为了调用的时候采用链式调用
public Builder setLeftText(String leftText) {
setText(R.id.tv_left, leftText);
return this;
}
public Builder setTitleText(String titleText) {
setText(R.id.tv_title, titleText);
return this;
}
public Builder setRightText(String rightText) {
setText(R.id.tv_right, rightText);
return this;
}
public Builder setLeftListener(View.OnClickListener leftListener) {
setOnClickListener(R.id.tv_left, leftListener);
return this;
}
public Builder setTitleListener(View.OnClickListener titleListener) {
setOnClickListener(R.id.tv_title, titleListener);
return this;
}
public Builder setRightListener(View.OnClickListener rightListener) {
setOnClickListener(R.id.tv_right, rightListener);
return this;
}
}
}
这里是我们采用了链式调用,很明显调用和我们的实现相分离,极大程度上解耦,调用者不用关系Builder是怎么实现的,
只需要传入对应的参数就可以把想要的东西设置在标题栏上,当我们业务需求增加的时候,直接修改DefaultNavigationBar这个类或者新增实现类即可,抽象类AbsNavigationBar作为基类就不用动它。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//这里是链式调用
DefaultNavigationBar navigationBar = new DefaultNavigationBar.Builder(this).setLeftText("返回1").setLeftListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
}).setTitleText("标题").setRightText("信息").create();
}
}
标题栏布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="100dp">
<TextView
android:id="@+id/tv_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:text="左"
android:textSize="30sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="MissingConstraints" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="标题"
android:textSize="30sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="MissingConstraints" />
<TextView
android:id="@+id/tv_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:layout_marginTop="20dp"
android:text="右"
android:textSize="30sp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
主页面布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="12312312"></TextView>
</LinearLayout>
运行效果:对比这两个图的效果,我们的activity的页面就作为内容部分在标题栏的下面,标题栏始终在上面,也就是说标题栏和内容模块是属于同级关系,不属于包含关系,不管我们怎么修改内容activity的内容布局等等,都不会影响到我们的标题栏,相当于两个View都互不影响,分离开了,这样子也算是解耦的一部分。
OKhttp源码详解(Builder设计模式)
看下面这段代码,是我们使用okhttp的常用写法,跟我们上面自己写的是一样的,链式调用法则,最后通过一个build的方法创建出来。
public class MainActivity extends AppCompatActivity {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//okhttp用法
//新建一个OkHttpClient的构造器Builder
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(100, TimeUnit.SECONDS).addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
return null;
}
}).readTimeout(100, TimeUnit.MINUTES);
}
}
接下来我们分析下它的源码
先再回顾一下建造者模式的定义:
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式将一个复杂对象的创建过程封装起来,允许对象通过多个步骤来创建,并且可以改变过程。尤其是在对象特别复杂,内部参数及其多的时候,建造者模式就能发挥出它的优势。若源代码中有Builder这个词,大概率使用了建造者模式。
注:这里我们用低版本的okhttp依赖分析源码,因为高版本的源码已经是kotlin了,很多人可能还不习惯kotlin,所以暂时先分析java版本的okhttp
/**
OkHttpClient就是我们说的复杂对象,内部包含一系列简单对象超时时间(Timeout),分发器(dispatcher),拦截器(interceptors)等等。
*/
public class OkHttpClient implements Cloneable, Call.Factory, WebSocketCall.Factory {
//我们实例化的构造函数
public OkHttpClient() {
//往下调用
this(new Builder());
}
//调用到这个构造函数
//下面我们看到的这些就是一个个的简单对象通过builder这个对象去赋值的
OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
this.connectionSpecs = builder.connectionSpecs;
this.interceptors = Util.immutableList(builder.interceptors);
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
this.eventListenerFactory = builder.eventListenerFactory;
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
boolean isTLS = false;
for (ConnectionSpec spec : connectionSpecs) {
isTLS = isTLS || spec.isTls();
}
if (builder.sslSocketFactory != null || !isTLS) {
this.sslSocketFactory = builder.sslSocketFactory;
this.certificateChainCleaner = builder.certificateChainCleaner;
} else {
X509TrustManager trustManager = systemDefaultTrustManager();
this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
}
this.hostnameVerifier = builder.hostnameVerifier;
this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
certificateChainCleaner);
this.proxyAuthenticator = builder.proxyAuthenticator;
this.authenticator = builder.authenticator;
this.connectionPool = builder.connectionPool;
this.dns = builder.dns;
this.followSslRedirects = builder.followSslRedirects;
this.followRedirects = builder.followRedirects;
this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
this.connectTimeout = builder.connectTimeout;
this.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;
this.pingInterval = builder.pingInterval;
if (interceptors.contains(null)) {
throw new IllegalStateException("Null interceptor: " + interceptors);
}
if (networkInterceptors.contains(null)) {
throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
}
}
public Builder newBuilder() {
return new Builder(this);
}
// Builder类
public static final class Builder {
//OkHttpClient.Builder的默认无参构造方法还设置了默认的参数初始值,我们在调用的时候如果没有传入参数那么就会使用它默认值。
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
Builder(OkHttpClient okHttpClient) {...... }
//Builder类的OkHttpClient,这里调用Builder.build()方法将Builder对象传递到OkHttpClient的构造方法里完成对象的创建。
public OkHttpClient build() {
return new OkHttpClient(this);
}
}
}
优点:
-
对象的创建和对象的展示分离开了,怎么说这个,OkHttpClient负责对外提供给别人调用,Builder负责对象的创建,符合职责分离。
-
Builder类默认的成员变量会对OkhttpClient的创建所需的对象进行一些默认创建初始化,对外会提供一些传入参数的方法,让调用者也能灵活控制一些OkhttpClient的创建过程,第三方调用不配置参数的时候就是使用Builder无参构造里面的默认参数值。
AlertDialog源码详解(Builder设计模式)
一般情况我们先看怎么使用它,很明显它也是采用链式调用,所以第一反映用了建造者模式,核心在Builder类里面,我们去看看。
public class MainActivity extends AppCompatActivity {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog alertDialog = builder.create();
//构造样式,标题,信息,按钮等等
builder.setTitle("确认").setMessage("确定吗?")
.setPositiveButton("是", null)
.setNegativeButton("否", null).show();
}
}
Builder类,源码很多我们就不列举完了,主要看一些重要部分。
public static class Builder {
//这个p就是我们设置set方法,第三方调用的对象的引用
private final AlertController.AlertParams P;
private final int mTheme;
public Builder(@NonNull Context context) {
this(context, resolveDialogTheme(context, 0));
}
public Builder(@NonNull Context context, @StyleRes int themeResId) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, themeResId)));
mTheme = themeResId;
}
@NonNull
public Context getContext() {
return P.mContext;
}
public Builder setTitle(@StringRes int titleId) {
P.mTitle = P.mContext.getText(titleId);
return this;
}
public Builder setTitle(@Nullable CharSequence title) {
P.mTitle = title;
return this;
}
......
public Builder setPositiveButton(@StringRes int textId, final OnClickListener listener) {
P.mPositiveButtonText = P.mContext.getText(textId);
P.mPositiveButtonListener = listener;
return this;
}
//创建了Dialog对象
@NonNull
public AlertDialog create() {
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);
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;
}
}
进入到AlertParams里面看看,这里大部分都是set方法,也就是我们调用的时候想要设置自己想要的参数的地方,它这里经过apply函数的处理,都交给了一个AlertController类型的对象,进去看看它是什么。
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);
}
if (mIconAttrId != 0) {
dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
}
}
if (mMessage != null) {
dialog.setMessage(mMessage);
}
if (mPositiveButtonText != null || mPositiveButtonIcon != null) {
dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
mPositiveButtonListener, null, mPositiveButtonIcon);
}
if (mNegativeButtonText != null || mNegativeButtonIcon != null) {
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
mNegativeButtonListener, null, mNegativeButtonIcon);
}
if (mNeutralButtonText != null || mNeutralButtonIcon != null) {
dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
mNeutralButtonListener, null, mNeutralButtonIcon);
}
// For a list, the client can either supply an array of items or an
// adapter or a cursor
if ((mItems != null) || (mCursor != null) || (mAdapter != null)) {
createListView(dialog);
}
if (mView != null) {
if (mViewSpacingSpecified) {
dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
mViewSpacingBottom);
} else {
dialog.setView(mView);
}
} else if (mViewLayoutResId != 0) {
dialog.setView(mViewLayoutResId);
}
}
AlertController类,仔细观察我们会发现,AlertParams 是它的静态内部类,AlertParams 的属性和AlertController的成员属性是一样的,在我们第三方应用者调用set方法设置属性参数值的时候,其实我们一开始调用的是private final AlertController.AlertParams P; P这个引用指向的对象,也就是一开始先给AlertParams 的成员属性赋值。
class AlertController {
private final Context mContext;
final AppCompatDialog mDialog;
private final Window mWindow;
private final int mButtonIconDimen;
private CharSequence mTitle;
private CharSequence mMessage;
ListView mListView;
private View mView;
private int mViewLayoutResId;
private int mViewSpacingLeft;
private int mViewSpacingTop;
private int mViewSpacingRight;
private int mViewSpacingBottom;
private boolean mViewSpacingSpecified = false;
Button mButtonPositive;
private CharSequence mButtonPositiveText;
Message mButtonPositiveMessage;
private Drawable mButtonPositiveIcon;
Button mButtonNegative;
private CharSequence mButtonNegativeText;
Message mButtonNegativeMessage;
private Drawable mButtonNegativeIcon;
Button mButtonNeutral;
private CharSequence mButtonNeutralText;
Message mButtonNeutralMessage;
private Drawable mButtonNeutralIcon;
NestedScrollView mScrollView;
private int mIconId = 0;
private Drawable mIcon;
private ImageView mIconView;
private TextView mTitleView;
private TextView mMessageView;
private View mCustomTitleView;
ListAdapter mAdapter;
int mCheckedItem = -1;
private int mAlertDialogLayout;
private int mButtonPanelSideLayout;
int mListLayout;
int mMultiChoiceItemLayout;
int mSingleChoiceItemLayout;
int mListItemLayout;
private boolean mShowTitle;
private int mButtonPanelLayoutHint = AlertDialog.LAYOUT_HINT_NONE;
Handler mHandler;
。。。。。。
}
调用了builder 的show方法之后,进去show方法看看,
//我们在应用上面的调用
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog alertDialog = builder.create();
builder.setTitle("确认").setMessage("确定吗?").setPositiveButton("是", null).setNegativeButton("否", null).show();
//进入show方法,发现它调用的是dialog.show();再进入到create看看
public AlertDialog show() {
final AlertDialog dialog = create();
dialog.show();
return dialog;
}
//这里是实例化了一个AlertDialog,dialog.mAlert,这个就是final AlertController mAlert;是AlertDialog的成员变量,传入到我们上面说的apply方法中去,P就是前面我们说的AlertParams这个静态内部类的引用,在apply中都把AlertParams中的值赋值到AlertController的成员变量中,类似就是在AlertParams中做了一个缓存操作把,这里大家如果忘记了apply可以回上面去看看,主要是做set操作。
@NonNull
public AlertDialog create() {
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);
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;
}
优点:可以看出来AlertController是一个复杂的产品对象,它包含着许多简单对象,通过Builder进行构建对象,解决了我们Dialog上要展示多种效果的问题,不用每次都书写重复的代码。