今天给大家介绍android -Dialog源码分析
Dialog 是所有对话框的基类,例如AlertDialog,我们要深入了解指导Dialog的用法,逻辑,必须要把Dilaog弄清楚,下面首先我们来看下Google对Dialog的类描述:
/**
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
*/
通过上面的描述,我们知道有2点重要的信息
1、Acitivity给我们提供了创建,预创建,展示,取消对话框的框架,在这个框架中我们不必担心额外的异常,这写方法包括:
onCreateDialog(int) :创建Dialog过程中要回调
onPrepareDialog(int, Dialog):准备创建对话框过程中要回调
showDialog(int):展示对话框
dismissDialog(int):取消对话框
这里很简单,大家可以自行阅读源码
2、WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 这个是WindowManager里面的flag标志位,当setFlag(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM );之后WindowManager中的EditText自动获取控件,将会获得焦点,有个相反的Flag就是,WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,设置之后WindowManager中的视图将得不到任务焦点。
接下来我看看Dialog的构造方法:
public Dialog(Context context, int theme) {
this(context, theme, true);
}
Dialog(Context context, int theme, boolean createContextThemeWrapper) {
if (createContextThemeWrapper) {
if (theme == 0) {
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme,
outValue, true);
theme = outValue.resourceId;
}
mContext = new ContextThemeWrapper(context, theme);
} else {
mContext = context;
}
mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Window w = PolicyManager.makeNewWindow(mContext);
mWindow = w;
w.setCallback(this);
w.setOnWindowDismissedCallback(this);
w.setWindowManager(mWindowManager, null, null);
w.setGravity(Gravity.CENTER);
mListenersHandler = new ListenersHandler(this);
}
Dialog的另外两个构造方法最终都要调用的这个方法,只不过在第三个参数为True,
public Dialog(Context context) {
this(context, 0, true);
}
public Dialog(Context context, int theme) {
this(context, theme, true);
}
,所以我们先来分析下这个构造方法,首先看到了这个createContextThemeWrapper 参数,这个参数为true的话 dialog会查找系统的主题资源文件id,来初始化context。
如果theme==0,那么就查找theme,
if (theme == 0) { TypedValue outValue = new TypedValue(); context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme, outValue, true); theme = outValue.resourceId; }
这里有个类TypedValue ,这个类主要是动态的表示和存储不同类型数据的容器,例如,系统资源resourceId,density,data,各种单位转化,例如,sp,dip,px,等等,这个类里面有个我们常用的方法:public static float applyDimension(int unit, float value, DisplayMetrics metrics) { switch (unit) { case COMPLEX_UNIT_PX: return value; case COMPLEX_UNIT_DIP: return value * metrics.density; case COMPLEX_UNIT_SP: return value * metrics.scaledDensity; case COMPLEX_UNIT_PT: return value * metrics.xdpi * (1.0f/72); case COMPLEX_UNIT_IN: return value * metrics.xdpi; case COMPLEX_UNIT_MM: return value * metrics.xdpi * (1.0f/25.4f); } return 0; }
来实现不同单位下的转化。
然后下面有这么一句context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme,
outValue, true);
这句里面其实是在查找resourceId,最后赋值到TypedValue 里面,Android系统里面系统资源的查找主要有2个类来实现一个是,Resources,和AssetManager,他们的主要区别是,Resources主要是通过资源id来查找资源,例如各种getText(int id),getDrawable(int id),getXml…都是通过id来查找的,而AssetManager,则是通过文件名字来查找的,
mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
获得窗口管理者,负责对窗口中添加视图和移除视图,
Window w = PolicyManager.makeNewWindow(mContext);
在这里创建了一个窗口类,我们可以看到这里有个PolicyManager类,这其实是个创建窗口的工厂类,我们看看源码:
public final class PolicyManager {
30 private static final String POLICY_IMPL_CLASS_NAME =
31 "com.android.internal.policy.impl.Policy";
32
33 private static final IPolicy sPolicy;
34
35 static {
36 // Pull in the actual implementation of the policy at run-time
37 try {
38 Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
39 sPolicy = (IPolicy)policyClass.newInstance();
40 } catch (ClassNotFoundException ex) {
41 throw new RuntimeException(
42 POLICY_IMPL_CLASS_NAME + " could not be loaded", ex);
43 } catch (InstantiationException ex) {
44 throw new RuntimeException(
45 POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
46 } catch (IllegalAccessException ex) {
47 throw new RuntimeException(
48 POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
49 }
50 }
51
52 // Cannot instantiate this class
53 private PolicyManager() {}
54
55 // The static methods to spawn new policy-specific objects
56 public static Window makeNewWindow(Context context) {
57 return sPolicy.makeNewWindow(context);
58 }
59
60 public static LayoutInflater makeNewLayoutInflater(Context context) {
61 return sPolicy.makeNewLayoutInflater(context);
62 }
63
64 public static WindowManagerPolicy makeNewWindowManager() {
65 return sPolicy.makeNewWindowManager();
66 }
67
68 public static FallbackEventHandler More ...makeNewFallbackEventHandler(Context context) {
69 return sPolicy.makeNewFallbackEventHandler(context);
70 }
71}
在这个类里面,我们首先会看到IPolicy,IPolicy是一个代理接口,
public interface IPolicy {
32 public Window makeNewWindow(Context context);
33
34 public LayoutInflater makeNewLayoutInflater(Context context);
35
36 public WindowManagerPolicy makeNewWindowManager();
37
38 public FallbackEventHandler makeNewFallbackEventHandler(Context context);
39}
这个接口有三个方法,makeNewWindow()创建一个新窗口,makeNewLayoutInflater创建LayoutInflater ,makeNewWindowManager 窗口管理代理,makeNewFallbackEventHandler,创建FallbackEventHandler 手机回退处理接口,FallbackEventHandler 的实现类有PhoneFallbackEventHandler
IPolicy 在static语句块中用反射实例化了com.android.internal.policy.impl.Policy,然后通过这个实例来创建窗口操作。
com.android.internal.policy.impl.Policy,通过这个我们指导IPolicy 的实现类是Policy ,我们看看Policy
public class More ...Policy implements IPolicy {
35 private static final String TAG = "PhonePolicy";
36
37 private static final String[] preload_classes = {
38 "com.android.internal.policy.impl.PhoneLayoutInflater",
39 "com.android.internal.policy.impl.PhoneWindow",
40 "com.android.internal.policy.impl.PhoneWindow$1",
41 "com.android.internal.policy.impl.PhoneWindow$DialogMenuCallback",
42 "com.android.internal.policy.impl.PhoneWindow$DecorView",
43 "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState",
44 "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState",
45 };
46
47 static {
48 // For performance reasons, preload some policy specific classes when
49 // the policy gets loaded.
50 for (String s : preload_classes) {
51 try {
52 Class.forName(s);
53 } catch (ClassNotFoundException ex) {
54 Log.e(TAG, "Could not preload class for phone policy: " + s);
55 }
56 }
57 }
58
59 public Window More ...makeNewWindow(Context context) {
60 return new PhoneWindow(context);
61 }
62
63 public LayoutInflater More ...makeNewLayoutInflater(Context context) {
64 return new PhoneLayoutInflater(context);
65 }
66
67 public WindowManagerPolicy More ...makeNewWindowManager() {
68 return new PhoneWindowManager();
69 }
70
71 public FallbackEventHandler More ...makeNewFallbackEventHandler(Context context) {
72 return new PhoneFallbackEventHandler(context);
73 }
74}在static里面会提前加载会用到的类,到此我们知道了PolicyManager.makeNewWindow(mContext);最终是是Policy通过直接实例化了PhoneWindow来生成的,android中的window类是抽象类,定义了窗口的行为,和部分实现,他们的实现类为PhoneWindow,在这里面我可以猜到,android系统要适配平板的话应该是有PadWindow,如果是手表的话估计有WatchWindow,具体的PhoneWindow的逻辑会在以后的文章深入分析。
继续接到前面讲,mWindow = w;设置dialog的mWindow ,w.setCallback(this);设置dialog中mWindow 的回调实现,这样dialog就具有类window的行为,比如我们按back dialog就会关闭等等。
w.setOnWindowDismissedCallback(this);设置dialog关闭行为回调,
mListenersHandler = new ListenersHandler(this);实例化ListenersHandler,ListenersHandler是继承Handler,负责dialog的show,cancel,dismiss的消息接受回调,具体Handler,机制可自行查阅资料,这里不在详述。
下面我们来看看dialog是如何展示到Activity中的。
首先我们看看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) {
dispatchOnCreate(null);
}
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 {
mWindowManager.addView(mDecor, l);
mShowing = true;
sendShowMessage();
} finally {
}
}
/**
* Hide the dialog, but do not dismiss it.
*/
public void hide() {
if (mDecor != null) {
mDecor.setVisibility(View.GONE);
}
}
逻辑还是很清晰的,首先判断根据if (mShowing) { 从mWindow获得dialog的布局属性信息,然后配置SOFT_INPUT_IS_FORWARD_NAVIGATION,这个Flag就是让窗口显示在最前面,这个信息一般有系统完成设置,l.softInputMode 终于到了dialog的展示语句了,mWindowManager将mDecor视图添加如了窗口中,那么dialog就展示在了我们面前,mWindowManager的实现类是WindowManagerImpl,所以addView()是在WindowManagerImpl中实现的,那么我们看看是怎么实现的。 applyDefaultToken(params); 如果IBinder为null则设置默认的IBinder,IBinder是FrameWork和Wms的通信桥梁,具体怎么实现的我还在继续学习研究,mGlobal.addView(view, params, mDisplay, mParentWindow);真正的添加动作是 WindowManagerGlobal完成的,下面这张图看以看出WindowManagerGlobal的位置 if (Looper.myLooper() == mHandler.getLooper()) { 如果视图不存在或者根本就没有展示出来,就不用管了, 如果窗口被销毁了 也就不管了 mWindowManager立刻执行移除视图操作,finally中最后处理操作,回调onStop(),调用dialog消失回调接口,更改mShowing状态。 AlertDialog是一个典型的建造者模式,通过Builder来构造AlertDialog,在构造过程中是通过AlertController来管理视图和属性的.下面是一个典型的展示代码: AlertDialog 可以展示Text文本对话框,带有EditText对话框,单选对话框,多选对话框,列表对话。 首先我们看到了resolveDialogTheme(context, 0) 方法,我们看看, 咋这个方法中主要是按照条件设置主题,在AlertDialog中系统给我们提供了,几种主题可以选择, 如果不是系统的选择,那么就使用用户自己定义的主题, 如果都不是上面的选择,也不是自定义的,那么系统将给出默认的主题,com.android.internal.R.attr.alertDialogTheme,这种属性主题最终通过AssetManager来查找的mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);然后将查找的内容存到TypedValue中,这个在上面的内容中也详细的讲过了。 你看就是赋值而已,那么最终这个属性是在哪里用呢 我们继续跟踪, 我们看到了,如果mAlwaysReadCloseOnTouchAttr ==true或者版本大于等于VERSION_CODES.HONEYCOMB(蜂巢,就是3…0版本啦),然后里面继续判断如果窗口风格设置Window_windowCloseOnTouchOutside了就setCloseOnTouchOutsideIfNotSet(true);而setCloseOnTouchOutsideIfNotSet(true) 方法是在Window中实现的 主要就是设置mCloseOnTouchOutside 和mSetCloseOnTouchOutside 为true。 然后我们纵观整个AlertDialog,2点重要发现。 例如还有,createListView(final AlertController dialog) 创建ListView,就是AlertDialog中的多选,单选,列表视图的初始化,所以AlertController结构还是很简单的。 AlertDialog的介绍就是这么多了,AlertDialog很方面的实现警告对话框,也就是说仅仅是警告对话框,很多时候他的布局是死的,远远不能满足我们需求,我们都会继承Dialog来自定义自己的dialog,还可以对设置的View设置动画,提高用户体验,那就发挥大家的想象吧!
if (mDecor != null) {
if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
}
mDecor.setVisibility(View.VISIBLE);
}
return;
}
判断是否dialog正在展示,如果展示的话就 判断dialog是否有actionbar,如果有的话就初始化,然后显示,你可能要问actionbar是什么东西,就是最上面有各icon和名字的标题界面,我们的layout文件初始化的时候就能看到那个东西,dialog也是可以设置的。
然后mCanceled = false;,因为正要展示dialog,当然不能被取消了啊,只有在展示完了之后才可以消失操作,
mDecor = mWindow.getDecorView();设置dialog的mDecor 属性,每个窗口都有一个根视图,所以mDecor 也是dialog的根视图,dialog上的View都是mDecor 的子视图,这个概念在Activity中也存在。
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);
}
如果dialog设置了FEATURE_ACTION_BAR,那么给actionbar设置默认的icon和logo,这里有ApplicationInfo类,这个类描述了Mainifest.xml的配置信息,这个类也可以通过context.getPackageManager();进一步获得,icon,logo就是我们在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;
}
& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0
在android系统中有很多的flag都是通过这种方式来存储和判断的,一来节省内存提高速度,二来方便逻辑操作,语法优美,在上面这断话是通过按位与操作符,来判SOFT_INPUT_IS_FORWARD_NAVIGATION是否存在,==0则不存在,具体为什么,稍微想下很好理解
WindowManager.LayoutParams 是描述窗口的位置,水平、垂直权重、窗口类型Type、窗口UI交互等众多配置信息的类Flag、例如FLAG_DIM_BEHIND,这个flag控制Window背景是否变暗(dialog就有这个属性),FLAG_NOT_FOCUSABLE设置window不要获取焦点,这样里面的editText不可以输入等等,我以后会在其它文章详细介绍。 try {
mWindowManager.addView(mDecor, l);
mShowing = true;
sendShowMessage();
} finally {
}
82 @Override
83 public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
84 applyDefaultToken(params);
85 mGlobal.addView(view, params, mDisplay, mParentWindow);
86 }
public final class WindowManagerImpl implements WindowManager { 49 private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); 50 private final Display mDisplay; 51 private final Window mParentWindow; 52 53 private IBinder mDefaultToken;
具体WindowManagerGlobal中addView是怎么添加的,以后的文章会详细讲解。
sendShowMessage(); 这个方法是通知事件的回调例如展示,取消等等,Message.obtain(mShowMessage).sendToTarget();发送各种消息。
下面我们来分析下dismiss(),dialog如何消失的,public void dismiss() {
if (Looper.myLooper() == mHandler.getLooper()) {
dismissDialog();
} else {
mHandler.post(mDismissAction);
}
}
void dismissDialog() {
if (mDecor == null || !mShowing) {
return;
}
if (mWindow.isDestroyed()) {
Log.e(TAG, "Tried to dismissDialog() but the Dialog's window was already destroyed!");
return;
}
try {
mWindowManager.removeViewImmediate(mDecor);
} finally {
if (mActionMode != null) {
mActionMode.finish();
}
mDecor = null;
mWindow.closeAllPanels();
onStop();
mShowing = false;
sendDismissMessage();
}
}
dismissDialog();
} else {
mHandler.post(mDismissAction);
}
在主线程和子线程都可以安全关闭对话框void dismissDialog() {
if (mDecor == null || !mShowing) {
return;
}
if (mWindow.isDestroyed()) {
Log.e(TAG, "Tried to dismissDialog() but the Dialog's window was already destroyed!");
return;
}
try {
mWindowManager.removeViewImmediate(mDecor);
} finally {
if (mActionMode != null) {
mActionMode.finish();
}
mDecor = null;
mWindow.closeAllPanels();
onStop();
mShowing = false;
sendDismissMessage();
}
剩下的其它方法有一部分是Window.Callback,
KeyEvent.Callback, OnCreateContextMenuListener, Window.OnWindowDismissedCallback
接口中的方法,
还有一部分是PhoneWindow中的方法
接下来我来看看Dialog的一个实现类AlertDialog,警告对话框。AlertDialog
new AlertDialog.Builder(self)
.setTitle("标题")
.setMessage("简单消息框")
.setPositiveButton("确定", null)
.show();
AlertDialog 的构造方法如下 protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
super(context, resolveDialogTheme(context, 0));
mWindow.alwaysReadCloseOnTouchAttr();
setCancelable(cancelable);
setOnCancelListener(cancelListener);
mAlert = new AlertController(context, this, getWindow());
}
static int resolveDialogTheme(Context context, int resid) {
if (resid == THEME_TRADITIONAL) {
return com.android.internal.R.style.Theme_Dialog_Alert;
} else if (resid == THEME_HOLO_DARK) {
return com.android.internal.R.style.Theme_Holo_Dialog_Alert;
} else if (resid == THEME_HOLO_LIGHT) {
return com.android.internal.R.style.Theme_Holo_Light_Dialog_Alert;
} else if (resid == THEME_DEVICE_DEFAULT_DARK) {
return com.android.internal.R.style.Theme_DeviceDefault_Dialog_Alert;
} else if (resid == THEME_DEVICE_DEFAULT_LIGHT) {
return com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog_Alert;
} else if (resid >= 0x01000000) { // start of real resource IDs.
return resid;
} else {
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
outValue, true);
return outValue.resourceId;
}
}
THEME_TRADITIONAL:透明主题
THEME_HOLO_DARK:全黑色主题
THEME_HOLO_LIGHT:全亮色主题
THEME_DEVICE_DEFAULT_DARK:设备默认黑色主题
THEME_DEVICE_DEFAULT_LIGHT:设备默认亮色主题
在这里面我们看到了HOLO字样,这个其实是Android 系统在4.0后推出的新主题风格,这种主题分为黑色和亮色系和混合系列,在很多的控件都有这种主题可以选择,dialog只是其中一种而已。else if (resid >= 0x01000000) { // start of real resource IDs.
return resid;
}这里写代码片
else {
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
outValue, true);
return outValue.resourceId;
}
接下来我们看到了mWindow.alwaysReadCloseOnTouchAttr();这个我们看名字也大概猜到了什么作用呢,应该是在点击窗口外面关闭窗口,的确是这样,这个是在Window中的一个抽象方法,具体的实现是PhoneWindow中的,在PhoneWindow中的实现是很简单的 public void More ...alwaysReadCloseOnTouchAttr() {
3548 mAlwaysReadCloseOnTouchAttr = true;
3549 }
if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
3368 >= android.os.Build.VERSION_CODES.HONEYCOMB) {
3369 if (a.getBoolean(
3370 R.styleable.Window_windowCloseOnTouchOutside,
3371 false)) {
3372 setCloseOnTouchOutsideIfNotSet(true);
3373 }
3374 }
public void More ...setCloseOnTouchOutsideIfNotSet(boolean close) {
889 if (!mSetCloseOnTouchOutside) {
890 mCloseOnTouchOutside = close;
891 mSetCloseOnTouchOutside = true;
892 }
893 }
构造方法接下来就是设置回调,和实例化AlertController了。
第一、AlertDialog只是个壳,真正的实现和管理控制都是通过AlertController来实现的,AlertController中的还有个AlertParams 类,AlertController主要是管理了相关的View和属性变量,很多方法都是对视图的初始化和设置,AlertParams 负责初始化工作例如里面有apply(AlertController dialog) 这个是初始化AlertDialog的方法,在AlertController的create中主要是它来实现的,public void More ...apply(AlertController dialog) {
949 if (mCustomTitleView != null) {
950 dialog.setCustomTitle(mCustomTitleView);
951 } else {
952 if (mTitle != null) {
953 dialog.setTitle(mTitle);
954 }
955 if (mIcon != null) {
956 dialog.setIcon(mIcon);
957 }
958 if (mIconId != 0) {
959 dialog.setIcon(mIconId);
960 }
961 if (mIconAttrId != 0) {
962 dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
963 }
964 }
965 if (mMessage != null) {
966 dialog.setMessage(mMessage);
967 }
968 if (mPositiveButtonText != null) {
969 dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
970 mPositiveButtonListener, null);
971 }
972 if (mNegativeButtonText != null) {
973 dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
974 mNegativeButtonListener, null);
975 }
976 if (mNeutralButtonText != null) {
977 dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
978 mNeutralButtonListener, null);
979 }
980 if (mForceInverseBackground) {
981 dialog.setInverseBackgroundForced(true);
982 }
983 // For a list, the client can either supply an array of items or an
984 // adapter or a cursor
985 if ((mItems != null) || (mCursor != null) || (mAdapter != null)) {
986 createListView(dialog);
987 }
988 if (mView != null) {
989 if (mViewSpacingSpecified) {
990 dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
991 mViewSpacingBottom);
992 } else {
993 dialog.setView(mView);
994 }
995 } else if (mViewLayoutResId != 0) {
996 dialog.setView(mViewLayoutResId);
997 }
998
999 /*
1000 dialog.setCancelable(mCancelable);
1001 dialog.setOnCancelListener(mOnCancelListener);
1002 if (mOnKeyListener != null) {
1003 dialog.setOnKeyListener(mOnKeyListener);
1004 }
1005 */
1006 }
第二、点就是AlertDialog一般都是通过内部类Builder来实例化的,通过点语法风格方便的写,AlertDialog的建造着模式是Android中很经典的。Builder 有create和show 和一大堆配置方法,写法结构很值得我们学习,建造者模式在Android其他地方也可以发现,例如BitmapFactory 图片工厂,ViewPropertyAnimator View的属性动画,