Dialog类的show方法里用到了WindowManager这个类。
Dialog.java
public void show() {
...
onStart();
mDecor = mWindow.getDecorView();
...
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 {
}
}
Dialog的内容视图最终是通过WindowManager显示到屏幕上的。因此接下来了解WindowManager的工作原理。这里有几个关键类,WindowManager、WindowManagerService(即WMS)、Surface、SurfaceFlinger
WindowManager属于在ContextImpl中静态map缓存的众多服务之一。
ContextImpl.java
static{
registerService(WINDOW_SERVICE, new ServiceFetcher() {
public Object getService(ContextImpl ctx) {
return WindowManagerImpl.getDefault(ctx.mPackageInfo.mCompatibilityInfo);
}});
}
WindowManagerImpl.java
private final static WindowManagerImpl sWindowManager = new WindowManagerImpl();
public static WindowManagerImpl getDefault() {
return sWindowManager;
}
那么Diolog是如何与WindowManager关联起来的呢?来看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);
...
}
可以看到通过Window实例的setWindowManager方法,将Window对象与WindowManager对象建立了联系。Window对象最终的mWindowManager是一个继承自WindowManagerImpl.CompatModeWrapper的LocalWindowManager对象,
Window.java
private WindowManager mWindowManager;
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
if (wm == null) {
wm = WindowManagerImpl.getDefault();
}
mWindowManager = new LocalWindowManager(wm, hardwareAccelerated);
}
private class LocalWindowManager extends WindowManagerImpl.CompatModeWrapper {
private static final String PROPERTY_HARDWARE_UI = "persist.sys.ui.hw";
LocalWindowManager(WindowManager wm, boolean hardwareAccelerated) {
super(wm, getCompatInfo(mContext));
}
public final void addView(View view, ViewGroup.LayoutParams params) {
// Let this throw an exception on a bad params.
WindowManager.LayoutParams wp = (WindowManager.LayoutParams)params;
CharSequence curTitle = wp.getTitle();
if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
if (wp.token == null) {
View decor = peekDecorView();
if (decor != null) {
wp.token = decor.getWindowToken();
}
}
if (curTitle == null || curTitle.length() == 0) {
String title;
if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA) {
title="Media";
} else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY) {
title="MediaOvr";
} else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
title="Panel";
} else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL) {
title="SubPanel";
} else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG) {
title="AtchDlg";
} else {
title=Integer.toString(wp.type);
}
if (mAppName != null) {
title += ":" + mAppName;
}
wp.setTitle(title);
}
} else {
if (wp.token == null) {
wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
}
if ((curTitle == null || curTitle.length() == 0)
&& mAppName != null) {
wp.setTitle(mAppName);
}
}
if (wp.packageName == null) {
wp.packageName = mContext.getPackageName();
}
if (mHardwareAccelerated) {
wp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
super.addView(view, params);
}
}
}
而这个CompatModeWrapper类是WindowManagerImpl的一个静态内部类,其实还是通过WindowManagerImpl的方法实现的addView等操作。只是多了一些参数
static class CompatModeWrapper implements WindowManager {
private final WindowManagerImpl mWindowManager;
CompatModeWrapper(WindowManager wm, CompatibilityInfoHolder ci) {
mWindowManager = wm instanceof CompatModeWrapper
? ((CompatModeWrapper)wm).mWindowManager : (WindowManagerImpl)wm;
...
}
@Override
public void addView(View view, android.view.ViewGroup.LayoutParams params) {
mWindowManager.addView(view, params, mCompatibilityInfo);
}
}
接下来看看WindowManagerImpl的核心代码
private void addView(View view, ViewGroup.LayoutParams params,
CompatibilityInfoHolder cih, boolean nest) {
...
final WindowManager.LayoutParams wparams
= (WindowManager.LayoutParams)params;
ViewRootImpl root;
root.setView(view, wparams, panelParentView);
}
最后一行root.setView(view, wparams, panelParentView);其实是用ViewRootImpl的setView方法将View显示到手机窗口中。
那么ViewRootImpl是什么呢?其实它不是个View,是继承自Handler。
public final class ViewRootImpl extends Handler implements ViewParent,
View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
public ViewRootImpl(Context context) {
//获取Window Session,也就是与WMS建立连接
getWindowSession(context.getMainLooper());
//保存当前线程,更新ui的线程只能是创建ViewRootImpl时的线程,也就是UI线程
//我们在应用开发中,如果在子线程中更新UI会抛出异常
//不是因为只有UI线程才能更新ui,而是ViewRootImpl是在ui线程中创建的
mThread = Thread.currentThread();
...
}
public static IWindowSession getWindowSession(Looper mainLooper) {
synchronized (mStaticInit) {
if (!mInitialized) {
try {
InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
sWindowSession = Display.getWindowManager().openSession(
imm.getClient(), imm.getInputContext());
mInitialized = true;
} catch (RemoteException e) {
}
}
return sWindowSession;
}
}
}
Display返回的WindowManager是个名为"window"的Service。
Display.java
static IWindowManager getWindowManager() {
synchronized (sStaticInit) {
if (sWindowManager == null) {
sWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
}
return sWindowManager;
}
}
ServiceManager.java
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
返回的其实是个IBinder对象,也就是说AndroidFrameWork与WMS也是通过Binder机制进行通信的。最后,通过openSessiton方法与WMS建立一个通信会话。双方有需要都通过这个Session来交换信息。
ViewRootImpl与WMS建立Session关联之后,接着是调用了setView方法,该方法会向WMS发起显示Dialog或Activity中的DecorView请求。可以看到ViewRootImpl的setView方法主要有两个事情:requestLayout,及向WMS发起显示当前Window的请求。代码如下:
ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
...
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
// 请求布局,绘制。
requestLayout();
...
try {
...
//向WMS发起请求显示当前Window.
res = sWindowSession.add(mWindow,mSeq, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets,
mInputChannel);
} catch (RemoteException e) {
...
}
if (res < WindowManagerImpl.ADD_OKAY) {
...
switch (res) {
case WindowManagerImpl.ADD_BAD_APP_TOKEN:
case WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN:
throw new WindowManagerImpl.BadTokenException(
"Unable to add window -- token " + attrs.token
+ " is not valid; is your activity running?");
...
}
...
}
}
public void requestLayout() {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
public void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
...
sendEmptyMessage(DO_TRAVERSAL);
}
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
...
case DO_TRAVERSAL:
...
performTraversals();
}
}
private final Surface mSurface = new Surface();
private void performTraversals() {
//这个方法有800多行代码,做了什么呢?
//1.获取Surface对象mSurface,用于图形的绘制
//2.丈量整个视图树的各个View大小,performMeasure方法
//3.布局整个视图树,performLayout方法
//4.绘制整个视图树,performDraw方法 draw(fullRedrawNeeded);
}
private void draw(boolean fullRedrawNeeded) {
Surface surface = mSurface;
...
if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
...
//使用硬件渲染器(GUP)绘制
if (mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this, currentDirty)) {
mPreviousDirty.set(0, 0, mWidth, mHeight);
}
return;
}
//使用CPU绘制图形
if (!dirty.isEmpty() || mIsAnimating) {
Canvas canvas;
try {
//1.获取绘制表面Surface对象
//通过Surface对象获取并锁住Canvas绘图对象
canvas = surface.lockCanvas(dirty);
...
try {
//2.从DecorView开始绘制,也就是整个Window的根视图,这会引起整棵树的重绘
mView.draw(canvas);
} finally {
}
}
...
} finally {
//3.释放Canvas锁,然后通知SurfaceFlinger更新到这块区域
surface.unlockCanvasAndPost(canvas);
}
}
...
}
...
Dialog.java
public void show() {
...
onStart();
mDecor = mWindow.getDecorView();
...
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 {
}
}
Dialog的内容视图最终是通过WindowManager显示到屏幕上的。因此接下来了解WindowManager的工作原理。这里有几个关键类,WindowManager、WindowManagerService(即WMS)、Surface、SurfaceFlinger
WindowManager属于在ContextImpl中静态map缓存的众多服务之一。
ContextImpl.java
static{
registerService(WINDOW_SERVICE, new ServiceFetcher() {
public Object getService(ContextImpl ctx) {
return WindowManagerImpl.getDefault(ctx.mPackageInfo.mCompatibilityInfo);
}});
}
WindowManagerImpl.java
private final static WindowManagerImpl sWindowManager = new WindowManagerImpl();
public static WindowManagerImpl getDefault() {
return sWindowManager;
}
那么Diolog是如何与WindowManager关联起来的呢?来看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);
...
}
可以看到通过Window实例的setWindowManager方法,将Window对象与WindowManager对象建立了联系。Window对象最终的mWindowManager是一个继承自WindowManagerImpl.CompatModeWrapper的LocalWindowManager对象,
Window.java
private WindowManager mWindowManager;
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
if (wm == null) {
wm = WindowManagerImpl.getDefault();
}
mWindowManager = new LocalWindowManager(wm, hardwareAccelerated);
}
private class LocalWindowManager extends WindowManagerImpl.CompatModeWrapper {
private static final String PROPERTY_HARDWARE_UI = "persist.sys.ui.hw";
LocalWindowManager(WindowManager wm, boolean hardwareAccelerated) {
super(wm, getCompatInfo(mContext));
}
public final void addView(View view, ViewGroup.LayoutParams params) {
// Let this throw an exception on a bad params.
WindowManager.LayoutParams wp = (WindowManager.LayoutParams)params;
CharSequence curTitle = wp.getTitle();
if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
if (wp.token == null) {
View decor = peekDecorView();
if (decor != null) {
wp.token = decor.getWindowToken();
}
}
if (curTitle == null || curTitle.length() == 0) {
String title;
if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA) {
title="Media";
} else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY) {
title="MediaOvr";
} else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
title="Panel";
} else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL) {
title="SubPanel";
} else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG) {
title="AtchDlg";
} else {
title=Integer.toString(wp.type);
}
if (mAppName != null) {
title += ":" + mAppName;
}
wp.setTitle(title);
}
} else {
if (wp.token == null) {
wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
}
if ((curTitle == null || curTitle.length() == 0)
&& mAppName != null) {
wp.setTitle(mAppName);
}
}
if (wp.packageName == null) {
wp.packageName = mContext.getPackageName();
}
if (mHardwareAccelerated) {
wp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
super.addView(view, params);
}
}
}
而这个CompatModeWrapper类是WindowManagerImpl的一个静态内部类,其实还是通过WindowManagerImpl的方法实现的addView等操作。只是多了一些参数
static class CompatModeWrapper implements WindowManager {
private final WindowManagerImpl mWindowManager;
CompatModeWrapper(WindowManager wm, CompatibilityInfoHolder ci) {
mWindowManager = wm instanceof CompatModeWrapper
? ((CompatModeWrapper)wm).mWindowManager : (WindowManagerImpl)wm;
...
}
@Override
public void addView(View view, android.view.ViewGroup.LayoutParams params) {
mWindowManager.addView(view, params, mCompatibilityInfo);
}
}
接下来看看WindowManagerImpl的核心代码
private void addView(View view, ViewGroup.LayoutParams params,
CompatibilityInfoHolder cih, boolean nest) {
...
final WindowManager.LayoutParams wparams
= (WindowManager.LayoutParams)params;
ViewRootImpl root;
root.setView(view, wparams, panelParentView);
}
最后一行root.setView(view, wparams, panelParentView);其实是用ViewRootImpl的setView方法将View显示到手机窗口中。
那么ViewRootImpl是什么呢?其实它不是个View,是继承自Handler。
public final class ViewRootImpl extends Handler implements ViewParent,
View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
public ViewRootImpl(Context context) {
//获取Window Session,也就是与WMS建立连接
getWindowSession(context.getMainLooper());
//保存当前线程,更新ui的线程只能是创建ViewRootImpl时的线程,也就是UI线程
//我们在应用开发中,如果在子线程中更新UI会抛出异常
//不是因为只有UI线程才能更新ui,而是ViewRootImpl是在ui线程中创建的
mThread = Thread.currentThread();
...
}
public static IWindowSession getWindowSession(Looper mainLooper) {
synchronized (mStaticInit) {
if (!mInitialized) {
try {
InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
sWindowSession = Display.getWindowManager().openSession(
imm.getClient(), imm.getInputContext());
mInitialized = true;
} catch (RemoteException e) {
}
}
return sWindowSession;
}
}
}
Display返回的WindowManager是个名为"window"的Service。
Display.java
static IWindowManager getWindowManager() {
synchronized (sStaticInit) {
if (sWindowManager == null) {
sWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
}
return sWindowManager;
}
}
ServiceManager.java
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
返回的其实是个IBinder对象,也就是说AndroidFrameWork与WMS也是通过Binder机制进行通信的。最后,通过openSessiton方法与WMS建立一个通信会话。双方有需要都通过这个Session来交换信息。
ViewRootImpl与WMS建立Session关联之后,接着是调用了setView方法,该方法会向WMS发起显示Dialog或Activity中的DecorView请求。可以看到ViewRootImpl的setView方法主要有两个事情:requestLayout,及向WMS发起显示当前Window的请求。代码如下:
ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
...
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
// 请求布局,绘制。
requestLayout();
...
try {
...
//向WMS发起请求显示当前Window.
res = sWindowSession.add(mWindow,mSeq, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets,
mInputChannel);
} catch (RemoteException e) {
...
}
if (res < WindowManagerImpl.ADD_OKAY) {
...
switch (res) {
case WindowManagerImpl.ADD_BAD_APP_TOKEN:
case WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN:
throw new WindowManagerImpl.BadTokenException(
"Unable to add window -- token " + attrs.token
+ " is not valid; is your activity running?");
...
}
...
}
}
public void requestLayout() {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
public void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
...
sendEmptyMessage(DO_TRAVERSAL);
}
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
...
case DO_TRAVERSAL:
...
performTraversals();
}
}
private final Surface mSurface = new Surface();
private void performTraversals() {
//这个方法有800多行代码,做了什么呢?
//1.获取Surface对象mSurface,用于图形的绘制
//2.丈量整个视图树的各个View大小,performMeasure方法
//3.布局整个视图树,performLayout方法
//4.绘制整个视图树,performDraw方法 draw(fullRedrawNeeded);
}
private void draw(boolean fullRedrawNeeded) {
Surface surface = mSurface;
...
if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
...
//使用硬件渲染器(GUP)绘制
if (mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this, currentDirty)) {
mPreviousDirty.set(0, 0, mWidth, mHeight);
}
return;
}
//使用CPU绘制图形
if (!dirty.isEmpty() || mIsAnimating) {
Canvas canvas;
try {
//1.获取绘制表面Surface对象
//通过Surface对象获取并锁住Canvas绘图对象
canvas = surface.lockCanvas(dirty);
...
try {
//2.从DecorView开始绘制,也就是整个Window的根视图,这会引起整棵树的重绘
mView.draw(canvas);
} finally {
}
}
...
} finally {
//3.释放Canvas锁,然后通知SurfaceFlinger更新到这块区域
surface.unlockCanvasAndPost(canvas);
}
}
...
}
...
}
整体结构如下图: