AndroidソースコードのAlertDialog分析
8976 ワード
前言:Androidソースで最もよく使われるBuilderモードは、AlertDialogです.複雑なAlertDialogオブジェクトを構築するためにBuilderを使用します.
まず、使い方を見てみましょう.
ビルダーで組み立てる.AlertDialogの関連ソースコードを見てみましょう.
上のコードでは、BuilderクラスでAlertDialogのレイアウトパラメータ、例えばtitle、messageなどを設定し、これらのパラメータを存在させます.
AlertParamsでは、AlertParamsには多くのDialogのレイアウトパラメータが含まれています.create()メソッドを呼び出すと、インスタンスが新しい
AlertDialogは、Builderメンバー変数のパラメータをapplyメソッドでAlerDialogのalertオブジェクトに適用します.私たちが
AlertDialogオブジェクトを取得すると、show関数でこのダイアログボックスが表示されます.
Builderのショー方法を見てみましょう.
show関数では主に以下のことをしました.
(1)dispatchOnCreate関数でAlertDialogのonCreate関数を呼び出す
(2)次にonStart関数を呼び出す
(3)最後にDialogのmDecorをWindowManagerに追加します(ここで一番上のレイアウトを取得する理由が少し分かりません)
したがって、ビューの作成は必ずonCreate()メソッド://DialogのonCreateメソッドは空の実装であるため、コールバックはサブクラスAlertDialogのonCreateメソッドである.
setupViewの役割は、AlertDialogレイアウトの各部分を初期化し、この関数を呼び出すとDialog全体のビューコンテンツが設定されます.これらの領域のビューはmAlertDialogLayoutのサブ要素に属し、Windowオブジェクトはレイアウトツリー全体に関連付けられています.setupViewを呼び出した後、ビューツリー全体のデータが埋め込まれ、show関数を呼び出すと、WindowManagerはWindowオブジェクトのDecorViewをユーザーウィンドウに追加して表示します.まとめ:AlerDialogのBuilderモードではDirectorロールは現れず、正式にはそのためプログラム全体が簡潔になった.デザインモデルは一種の思想であり、強引なカバーを生で運ぶべきではなく、柔軟に使用しなければならない.参考書:『Androidソースデザインモデル解析と実戦』
まず、使い方を見てみましょう.
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Title").setMessage("Message").setIcon(R.mipmap.ic_launcher).create().show();
この使用方法から見ると明らかにBuilderモードであり、内部の実装の詳細を外部に隠し、Dialogの各構成部分をビルダーで組み立てる.AlertDialogの関連ソースコードを見てみましょう.
public class AlertDialog extends AppCompatDialog implements DialogInterface {
// Builder P
private AlertController mAlert;
protected AlertDialog(Context context) {
this(context, resolveDialogTheme(context, 0), true);
}
protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
super(context, resolveDialogTheme(context, 0));
setCancelable(cancelable);
setOnCancelListener(cancelListener);
mAlert = new AlertController(context, this, getWindow());
}
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
mAlert.setTitle(title);
}
public void setCustomTitle(View customTitleView) {
mAlert.setCustomTitle(customTitleView);
}
public void setView(View view) {
mAlert.setView(view);
}
void setButtonPanelLayoutHint(int layoutHint) {
mAlert.setButtonPanelLayoutHint(layoutHint);
}
...... Set 。
public static class Builder {
// Dialog , :title,Message
private final AlertController.AlertParams P;
// Builder , Builder , P
Builder setTitle(CharSequence title) {
P.mTitle = title;
return this;
}
public Builder setCustomTitle(View customTitleView) {
P.mCustomTitleView = customTitleView;
return this;
}
public Builder setMessage(int messageId) {
P.mMessage = P.mContext.getText(messageId);
return this;
}
// AlertDialog
public AlertDialog create() {
// AlertDialog
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
// P Dialog.mAlert , 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などを設定し、これらのパラメータを存在させます.
AlertParamsでは、AlertParamsには多くのDialogのレイアウトパラメータが含まれています.create()メソッドを呼び出すと、インスタンスが新しい
AlertDialogは、Builderメンバー変数のパラメータをapplyメソッドでAlerDialogのalertオブジェクトに適用します.私たちが
AlertDialogオブジェクトを取得すると、show関数でこのダイアログボックスが表示されます.
Builderのショー方法を見てみましょう.
public AlertDialog show() {
AlertDialog dialog = create();
dialog.show();
return dialog;
}
AlertDialog 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;
//1. , Dialog OnCreate
if (!mCreated) {
dispatchOnCreate(null);
}
//2. Dialog 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;
}
try {
// mDecor WindowManager
mWindowManager.addView(mDecor, l);
mShowing = true;
// Dialog
sendShowMessage();
} finally {
}
}
show関数では主に以下のことをしました.
(1)dispatchOnCreate関数でAlertDialogのonCreate関数を呼び出す
(2)次にonStart関数を呼び出す
(3)最後にDialogのmDecorをWindowManagerに追加します(ここで一番上のレイアウトを取得する理由が少し分かりません)
したがって、ビューの作成は必ずonCreate()メソッド://DialogのonCreateメソッドは空の実装であるため、コールバックはサブクラスAlertDialogのonCreateメソッドである.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAlert.installContent();
}
public void installContent() {
//
final int contentView = selectContentView();
mDialog.setContentView(contentView);
setupView();
}
private void setupView() {
// Window setContentView, Window setContentView
// AlertController , :alert_dialog.xml
final View parentPanel = mWindow.findViewById(R.id.parentPanel);
final View defaultTopPanel = parentPanel.findViewById(R.id.topPanel);
final View defaultContentPanel = parentPanel.findViewById(R.id.contentPanel);
final View defaultButtonPanel = parentPanel.findViewById(R.id.buttonPanel);
// Install custom content before setting up the title or buttons so
// that we can handle panel overrides.
//
final ViewGroup customPanel = (ViewGroup) parentPanel.findViewById(R.id.customPanel);
setupCustomContent(customPanel);
final View customTopPanel = customPanel.findViewById(R.id.topPanel);
final View customContentPanel = customPanel.findViewById(R.id.contentPanel);
final View customButtonPanel = customPanel.findViewById(R.id.buttonPanel);
// Resolve the correct panels and remove the defaults, if needed.
final ViewGroup topPanel = resolvePanel(customTopPanel, defaultTopPanel);
final ViewGroup contentPanel = resolvePanel(customContentPanel, defaultContentPanel);
final ViewGroup buttonPanel = resolvePanel(customButtonPanel, defaultButtonPanel);
//
setupContent(contentPanel);
//
setupButtons(buttonPanel);
//
setupTitle(topPanel);
// ,
final boolean hasCustomPanel = customPanel != null
&& customPanel.getVisibility() != View.GONE;
final boolean hasTopPanel = topPanel != null
&& topPanel.getVisibility() != View.GONE;
final boolean hasButtonPanel = buttonPanel != null
&& buttonPanel.getVisibility() != View.GONE;
// Only display the text spacer if we don't have buttons.
if (!hasButtonPanel) {
if (contentPanel != null) {
final View spacer = contentPanel.findViewById(R.id.textSpacerNoButtons);
if (spacer != null) {
spacer.setVisibility(View.VISIBLE);
}
}
}
if (hasTopPanel) {
// Only clip scrolling content to padding if we have a title.
if (mScrollView != null) {
mScrollView.setClipToPadding(true);
}
}
// Update scroll indicators as needed.
if (!hasCustomPanel) {
final View content = mListView != null ? mListView : mScrollView;
if (content != null) {
final int indicators = (hasTopPanel ? ViewCompat.SCROLL_INDICATOR_TOP : 0)
| (hasButtonPanel ? ViewCompat.SCROLL_INDICATOR_BOTTOM : 0);
setScrollIndicators(contentPanel, content, indicators,
ViewCompat.SCROLL_INDICATOR_TOP | ViewCompat.SCROLL_INDICATOR_BOTTOM);
}
}
// listview
final ListView listView = mListView;
if (listView != null && mAdapter != null) {
listView.setAdapter(mAdapter);
final int checkedItem = mCheckedItem;
if (checkedItem > -1) {
listView.setItemChecked(checkedItem, true);
listView.setSelection(checkedItem);
}
}
}
setupViewの役割は、AlertDialogレイアウトの各部分を初期化し、この関数を呼び出すとDialog全体のビューコンテンツが設定されます.これらの領域のビューはmAlertDialogLayoutのサブ要素に属し、Windowオブジェクトはレイアウトツリー全体に関連付けられています.setupViewを呼び出した後、ビューツリー全体のデータが埋め込まれ、show関数を呼び出すと、WindowManagerはWindowオブジェクトのDecorViewをユーザーウィンドウに追加して表示します.まとめ:AlerDialogのBuilderモードではDirectorロールは現れず、正式にはそのためプログラム全体が簡潔になった.デザインモデルは一種の思想であり、強引なカバーを生で運ぶべきではなく、柔軟に使用しなければならない.参考書:『Androidソースデザインモデル解析と実戦』