(一)AlertDialog的实现模式
AlertDialog的实现模式使用了Builder模式,通过Builder对象来组装Dialog的各个部分。AlertController用于存储Builder成员变量中的各个参数。
AlertDialog可以设置title,message,button等参数,这些参数存储在AlertController.AlertParams的成员变量P中,AlertController.AlertParams中包含了AlertDialog视图中对应的成员变量。Builder类在调用create函数时会创建AlertDialog,并将P中的保存的参数应用到AlertDialog的mAlert对象中。这个是通过P.apply函数来实现的。
在调用完create函数后,我们获取了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;
if (!mCreated) {
dispatchOnCreate(null);
} else {
// Fill the DecorView in on any configuration changes that
// may have occured while it was removed from the WindowManager.
final Configuration config = mContext.getResources().getConfiguration();
mWindow.getDecorView().dispatchConfigurationChanged(config);
}
onStart();
mDecor = mWindow.getDecorView();
//省略代码
mWindowManager.addView(mDecor, l);
mShowing = true;
sendShowMessage();
}
show函数执行了三个操作:
1.如果AlertDialog没有被create,就通过dispatchOnCreate调用了AlertDialog的onCreate方法
2.调用AlertDialog的onStart方法
3.将DecorView添加到WindowManager中
我们看一下onCreate方法的实现。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAlert.installContent();
}
然后我们看一下installContent()方法。
public void installContent() {
final int contentView = selectContentView();
mDialog.setContentView(contentView);
setupView();
}
这方法就实现了两步,(1)设置AlertDialog的内容布局(2)初始化AlertDialog布局中的各个部分。setupView中使用了大量的findViewById来寻找相关的组件,代码比较庞杂,对此我们就不一一看了。
(二)WindowManager
AlertDialog的视图最后是将view传递给WindowManger来显示的。事实上所有的要显示到屏幕上的内容(包括Activity)都是通过WindowManager来进行操作的。
WindowManager是ContextImpl中注册的众多服务之一。各种系统服务会注册到ContextImpl的一个map容器中,然后通过该服务的关键字来获取。
通过getSystemService方法获取到WindowManger对象后。我们该如何将Window对象和WindowManager建立联系呢。在Dialog的构造函数中,我们可以看到这么一行代码。
w.setWindowManager(mWindowManager, null, null);
我们看一下setWindowManager方法的具体实现。
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
//省略代码
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
WindowManagerImpl是WindowManagerGlobal的包装。我们在上一层,通过调用WindowManager的addView方法请求系统将该View显示到屏幕上,实际上这一切的实现都是通过WindowManagerGlobal的addView方法来实现的。
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
//代码省略
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
// If there's no parent, then hardware acceleration for this view is
// set from the application's hardware acceleration setting.
final Context context = view.getContext();
if (context != null
&& (context.getApplicationInfo().flags
& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
// Start watching for system property changes.
if (mSystemPropertyUpdater == null) {
mSystemPropertyUpdater = new Runnable() {
@Override public void run() {
synchronized (mLock) {
for (int i = mRoots.size() - 1; i >= 0; --i) {
mRoots.get(i).loadSystemProperties();
}
}
}
};
SystemProperties.addChangeCallback(mSystemPropertyUpdater);
}
int index = findViewLocked(view, false);
if (index >= 0) {
if (mDyingViews.contains(view)) {
// Don't wait for MSG_DIE to make it's way through root's queue.
mRoots.get(index).doDie();
} else {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
// The previous removeView() had not completed executing. Now it has.
}
// If this is a panel window, then find the window it is being
// attached to for future reference.
if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
final int count = mViews.size();
for (int i = 0; i < count; i++) {
if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
panelParentView = mViews.get(i);
}
}
}
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
}
// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
synchronized (mLock) {
final int index = findViewLocked(view, false);
if (index >= 0) {
removeViewLocked(index, true);
}
}
throw e;
}
}
这里构建了ViewRootImpl,将布局参数设置给View,存储ViewRootImpl,View,LayoutParam到列表中。然后通过ViewRootImpl的setView将View显示到窗口上。
ViewRootImpl实现了native层和Java层View系统通信的桥梁。它会检测系统中View的消息,并通过调用方法来绘制整棵视图树。我们看一下ViewRootImpl的构建方法。
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();
//省略代码
}
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
InputMethodManager imm = InputMethodManager.getInstance();
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
},
imm.getClient(), imm.getInputContext());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
public static IWindowManager getWindowManagerService() {
synchronized (WindowManagerGlobal.class) {
if (sWindowManagerService == null) {
sWindowManagerService = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
try {
sWindowManagerService = getWindowManagerService();
ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowManagerService;
}
}
从上文代码中可以看到,Android的架构层和native的wms是通过Binder机制进行通信的。架构层通过了Binder机制和Native建立了联系,并通过了openSession与WMS建立通行会话。
WMS管理的是View的Z轴。
在与WMS建立完联系后,我们会调用ViewRootImp的setView方法。该方法会向WMS发送显示Dialog或者Activity中的DecorView的请求,具体代码如下:
setView方法很复杂,但是主要逻辑是两步:
(1)requestLayout
(2)向WMS发送显示当前Window的请求
requestLayout方法会向handler中发送一个DO_TRAVERSAL消息,这个消息会触发整个视图树的绘制操作,简而言之就是遍历整棵树的各个View,执行了Measure,Layout,Draw方法。
总结:
架构层和native层通过binder来进行通信