Android系統封裝了AlertDialog,用來給我們使用。我們可以通過
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setTitle("Title")
.setMessage("message")
.create()
.show();
複製程式碼
這個其實就是典型的Builder設計模式,通過封裝複雜的dialog物件,將組建和構建分離,當使用者使用的時候可以直接呼叫組建,並最後建立出Dialog物件。
通過Dialog原始碼的分析,我們能夠更好的瞭解Builder設計模式。
public class AlertDialog extends Dialog implements DialogInterface {
private AlertController mAlert;
AlertDialog(Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
super(context, createContextThemeWrapper ? resolveDialogTheme(context, themeResId) : 0,
createContextThemeWrapper);
mWindow.alwaysReadCloseOnTouchAttr();
mAlert = new AlertController(getContext(), this, getWindow());
}
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
mAlert.setTitle(title);
}
public static class Builder {
public Builder(Context context, int themeResId) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, themeResId)));
}
public Builder setTitle(@StringRes int titleId) {
P.mTitle = P.mContext.getText(titleId);
return this;
}
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;
}
}
}
複製程式碼
通過上面的程式碼我們可以看到,建立AlertDialog.Build的時候會建立一個AlertController.AlertParams物件,這個物件裡面封裝了所有的Dialog的屬性,並且在呼叫Builder的類似於setTitle方法的時候會將引數賦值給AlertParams,當所有的元件的屬性賦值好之後,就呼叫create()方法,這個方法裡面就建立出AlertDialog物件,並呼叫P.apply(dialog.mAlert)方法,將AlertDialog建構函式建立出來的AlertController物件傳遞給P:
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中,當我們呼叫create方法的時候,就是講AlertDialog物件的元件組裝起來,當我呼叫show的時候就會呼叫dialog的show方法:
public void show() {
// 如果已經在顯示狀態,return
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);
}
onStart();
// 獲取DecorView
mDecor = mWindow.getDecorView();
// 獲取佈局引數
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;
}
// 將decorView新增到WindowManager中
mWindowManager.addView(mDecor, l);
mShowing = true;
// 傳送一個現實Dialog的訊息
sendShowMessage();
}
複製程式碼
在show方法中:
-
通過diapatchOnCreate方法,呼叫Dialog的onCreate方法,並最終呼叫installContent方法。
public void installContent() { /* We use a custom title so never request a window title */ mWindow.requestFeature(Window.FEATURE_NO_TITLE); // 設定視窗的檢視 int contentView = selectContentView(); mWindow.setContentView(contentView); setupView(); setupDecor(); } 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; } 複製程式碼
而我們可以看到在呼叫selectContentView的時候,會去獲取mButtonPanelSideLayout檢視,並通過WindowManager的setContentView方法來將檢視載入。
public AlertController(Context context, DialogInterface di, Window window) { final TypedArray a = context.obtainStyledAttributes(null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0); // 獲取檢視 mAlertDialogLayout = a.getResourceId( R.styleable.AlertDialog_layout, R.layout.alert_dialog); a.recycle(); } 複製程式碼
再通過setupView方法初始化AlertDialog佈局中的各個部分
-
呼叫AlertDialog的onStart方法
-
最後將DecorView新增到WindowManager中