在Android源码中,最常用到的Builder模式的就是AlertDialog.Builder.
public class AlertDialog extends AppCompatDialog implements DialogInterface {
final AlertController mAlert; //用来接收Builder成员变量P中的各个参数
static final int LAYOUT_HINT_SIDE = 1;
protected AlertDialog(@NonNull Context context) {
this(context, 0);
}
protected AlertDialog(@NonNull Context context, @StyleRes int themeResId) {
super(context, resolveDialogTheme(context, themeResId));
mAlert = new AlertController(getContext(), this, getWindow());
}
......................省略代码...................
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
//实际上是mAlert的setTitle方法
mAlert.setTitle(title);
}
Builder是AlertDialog 的内部类
public static class Builder {
private final AlertController.AlertParams P;
private final int mTheme;
public Builder(@NonNull Context context) {
this(context, resolveDialogTheme(context, 0));
}
//设置各种参数
public Builder setView(View view) {
P.mView = view;
P.mViewLayoutResId = 0;
P.mViewSpacingSpecified = false;
return this;
}
//构建AlertDialog,传递参数
public AlertDialog create() {
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);
//将p中的参数应用到dialog的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;
}
}
上述代码中,Builder设置AlertDialog中title、message、button等参数,这些参数都存储在AlertController.AlertParams P中,其中包含了与AlertDialog视图中对应的成员变量
看一下P.apply()方法
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));
}
}
在apply函数中,只是将AlertParams 参数设置到AlertController中,例如,将标题设置到Dialog对应的标题视图中,需要我们调用show()方法。
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) {
//来调用AlertDialog的oncreate()函数
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);
}
//调用Alert的onstart方法
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;
}
//将Dialog的DecorView添加到WindowManager中
mWindowManager.addView(mDecor, l);
mShowing = true;
sendShowMessage();
}
下面来看一下dispatchOnCreate()这个方法
void dispatchOnCreate(Bundle savedInstanceState) {
if (!mCreated) {
onCreate(savedInstanceState);//调用Dialog的oncreate,空方法, AlertDialog继承Dialog,其自身实现
mCreated = true;
}
}
AlertDialog的oncreate()方法
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAlert.installContent();
}
跳转进去,查看其方法
public void installContent() {
final int contentView = selectContentView();
mDialog.setContentView(contentView);
setupView();
}
调用setContentView和Activity的一样,这里设置AlertDialog的内容布局,这个内容布局就是mAlertDialogLayout字段的值,这个值在AlertController的构造函数中进行了初始化。
最后就是setupView()方法了,初始化AlertDialog布局中各个部分,Dialog视图部分设置完毕。 当用户调用show()方法时,WindowManager会将Window的DecorView(mAlertDialogLayout的视图), mWindowManager.addView(mDecor, l);添加到用户窗口上。
至此,Dialog就出现在用户的视野中了。。。。。