本文所引用的代码为Android 5.0(API 22)版本
Dialog类实现了DialogInterface, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, Window.OnWindowDismissedCallback这个五个接口。比较常用到的三个接口:Window.Callback是接收屏幕touch事件;KeyEvent.Callback为接收键盘按键事件和实体键消息;Window.OnWindowDismissedCallback为接收窗口消失回调。
本文从Dialog的创建,隐藏,显示和移除步骤来分析相关的代码流程。最后补充了几个常见的异常分析。
创建
看看构造方法代码:
//提供给外部调用人口
public Dialog(Context context) {
this(context, 0, true);
}
//提供给外部调用人口
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;
}
//获取WindowManagerImpl对象,这个对象一般为Activity的windowManger
mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
//创建PhoneWindow对象
Window w = PolicyManager.makeNewWindow(mContext);
//赋值,mWindow即PhoneWindow对象,不是WindowManger
mWindow = w;
设置Window.Callback回调
w.setCallback(this);
//window dismiss回调
w.setOnWindowDismissedCallback(this);
//调用Window的setWindowManager创建PhoneWindow内部的WindowMangerImpl
w.setWindowManager(mWindowManager, null, null);
//默认设置为居中
w.setGravity(Gravity.CENTER);
//接收异步消息的Handler
mListenersHandler = new ListenersHandler(this);
}
PolicyManager#makeNewWindow相关代码:
路径:/sources/android-22/com/android/internal/policy/PolicyManager.java
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}
sPolicy为Policy类的对象:
路径:/sources/android-22/com/android/internal/policy/impl/Policy.java
public Window makeNewWindow(Context context) {
return new PhoneWindow(context);
}
Window的setWindowManager方法相关代码:
public void setWindowManager(WindowManager wm, IBinder appToken, String appName) {
setWindowManager(wm, appToken, appName, false);
}
public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated
|| SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
显示
show方法代码:
public void show() {
if (mShowing) {
//dialog已调用过show方法,调用dismiss会设置为false
if (mDecor != null) {
if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
}
//显示Dialog的根View,即Dialog便可见
mDecor.setVisibility(View.VISIBLE);
}
return;
}
mCanceled = false;
if (!mCreated) {
dispatchOnCreate(null);
}
onStart();
//创建DecorView
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 {
//添加到当前显示的窗口,便可以看见dialog
mWindowManager.addView(mDecor, l);
mShowing = true;
//发送dialog显示消息
sendShowMessage();
} finally {
}
}
mDecor为DecorView对象,DecorView继承了FrameLayout。在Android 6.0以下版本,DecorView为PhoneWindow的内部类;6.0及以上版本,则被抽出,为一个独立的类。
我们在使用Dialog调用findViewById和setContentView方法,其实都是PhoneWindow中的方法在执行相应的操作。
Dialog中相关方法的代码:
public View findViewById(int id) {
return mWindow.findViewById(id);
}
public void setContentView(int layoutResID) {
mWindow.setContentView(layoutResID);
}
public void setContentView(View view) {
mWindow.setContentView(view);
}
public void setContentView(View view, ViewGroup.LayoutParams params) {
mWindow.setContentView(view, params);
}
public void addContentView(View