Builder模式类图:
AlertDialog采用了builder模式来构造。下面分析
//测试代码
private void showDialog(Context context){
AlertDialog dialog=new AlertDialog.Builder(context).setTitle("test")
.setIcon(R.drawable.icon).create();
dialog.show();
}
AlertDialog.Builder.java
public static class Builder {
private final AlertController.AlertParams P;
public Builder setTitle(CharSequence title) {
P.mTitle = title;
return this;
}
public AlertDialog create() {
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
if (P.mOnKeyListener != null) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
Dialog.java
Dialog(Context context, int theme, boolean createContextWrapper) {
...
mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Window w = PolicyManager.makeNewWindow(mContext);
mWindow = w;
w.setCallback(this);
w.setWindowManager(mWindowManager, null, null);
w.setGravity(Gravity.CENTER);
mUiThread = Thread.currentThread();
mListenersHandler = new ListenersHandler(this);
}
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) {
dispatchOnCreate(null);
}
onStart();
mDecor = mWindow.getDecorView();
if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
mActionBar = new ActionBarImpl(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;
}
try {
mWindowManager.addView(mDecor, l);
mShowing = true;
sendShowMessage();
} finally {
}
}
void dispatchOnCreate(Bundle savedInstanceState) {
if (!mCreated) {
onCreate(savedInstanceState);
mCreated = true;
}
}
protected void onCreate(Bundle savedInstanceState) {
}
来看看子类AlertDialog的实现
AlertDialog.java
private AlertController mAlert;
private View mView;
AlertDialog(Context context, int theme, boolean createContextWrapper) {
super(context, resolveDialogTheme(context, theme), createContextWrapper);
mWindow.alwaysReadCloseOnTouchAttr();
mAlert = new AlertController(getContext(), this, getWindow());
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAlert.installContent();
}
AlertController.java
public AlertController(Context context, DialogInterface di, Window window) {
mContext = context;
mDialogInterface = di;
mWindow = window;
...
mAlertDialogLayout = a.getResourceId(com.android.internal.R.styleable.AlertDialog_layout,
com.android.internal.R.layout.alert_dialog);
...
}
public void installContent() {
/* We use a custom title so never request a window title */
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
if (mView == null || !canTextInput(mView)) {
mWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
}
mWindow.setContentView(mAlertDialogLayout);
setupView();
}
原来是用了 mWindow.setContentView(mAlertDialogLayout);最终和之前的Activity一样,也是通过PhoneWindow对象,最终会调用mLayoutInflater.inflate方法进行布局。加载的布局是 com.android.internal.R.layout.alert_dialog.xml。当然AlertDialog也可以通过setView传入自定义的视图,会替换到图中的蓝色区域。
private void setupView() {
LinearLayout contentPanel = (LinearLayout) mWindow.findViewById(R.id.contentPanel);
setupContent(contentPanel);
boolean hasButtons = setupButtons();
LinearLayout topPanel = (LinearLayout) mWindow.findViewById(R.id.topPanel);
TypedArray a = mContext.obtainStyledAttributes(
null, com.android.internal.R.styleable.AlertDialog, com.android.internal.R.attr.alertDialogStyle, 0);
boolean hasTitle = setupTitle(topPanel);
View buttonPanel = mWindow.findViewById(R.id.buttonPanel);
if (!hasButtons) {
buttonPanel.setVisibility(View.GONE);
mWindow.setCloseOnTouchOutsideIfNotSet(true);
}
FrameLayout customPanel = null;
if (mView != null) {
customPanel = (FrameLayout) mWindow.findViewById(R.id.customPanel);
FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.custom);
custom.addView(mView, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
if (mViewSpacingSpecified) {
custom.setPadding(mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
mViewSpacingBottom);
}
if (mListView != null) {
((LinearLayout.LayoutParams) customPanel.getLayoutParams()).weight = 0;
}
} else {
mWindow.findViewById(R.id.customPanel).setVisibility(View.GONE);
}
/* Only display the divider if we have a title and a
* custom view or a message.
*/
if (hasTitle) {
View divider = null;
if (mMessage != null || mView != null || mListView != null) {
divider = mWindow.findViewById(R.id.titleDivider);
} else {
divider = mWindow.findViewById(R.id.titleDividerTop);
}
if (divider != null) {
divider.setVisibility(View.VISIBLE);
}
}
setBackground(topPanel, contentPanel, customPanel, hasButtons, a, hasTitle, buttonPanel);
a.recycle();
}