WindowManager 详解
一、概述
由于 WindowManager 是与 WindowManagerService (WMS) 关联紧密的类。因此,在分析 WMS前,我们先来分析一下 WindowManager 体系的相关知识。
下面从如下3个部分进行分析:
- WindowManager体系
- Window 的属性
- Window 的操作
版本: Android SDK 29
关联文章:
二、WindowManager 体系
1. 类图
WindowManager 体系如上图所示 (图片来源于网络)。
概念梳理:
- Window 是一个抽象概念,代表一个窗口,其具体的实现类为 PhoneWindow ,它对 View进行管理。
- WindowManager 是一个接口类,继承自接口 ViewManager,它是用来管理 Window 的。它的具体实现类为 WindowManagerImpI。
- WindowManagerGlobal 是实际操作的类,是一个单例,每个进程中只有一个实例对象,该实例对象在 WindowManagerGlobal 中。
- 在 WindowManagerGlobal 中,会创建 ViewRootImpl 实例对象,每个根 View 对应一个 ViewRootImpl 实例对象。
- 想要对 Window (View)进行添加、更新和删除操作,可以使用 WindowManager 来执行。最终的操作是通过 Binder 交给 WMS 来执行的。
2. 源码分析
2.1 ViewManager
的结构
可以看到,ViewManager 提供的三个方法都是将 View 作为参数传递进去的。
// 可以看到,ViewManager 提供的三个方法都是将 View 作为参数传递进去的。
public interface ViewManager{
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
2.2 PhoneWindow 对象何时创建?
问: 已知 Window 的具体实现类是 PhoneWindow ,那它是何时创建的呢?
.
答: 在Activity.attach()
方法中创建了 PhoneWindow 对象, Activity.attach() 方法又是在ActivityThread.performLaunchActivity()
方法中被触发,这部分可以参考 《源码分析 — Activity的启动流程》 。
Activity
// Activity
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
// 1.创建了PhoneWindow对象。
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
// 2.Activity 实现了 Window.Callback接口,会触发 Window 操作的相关回调(如 dispatchTouchEvent方法)。
mWindow.setCallback(this);
// ...省略代码...
// 3.将 Window 与 WindowManager 关联起来。
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
// 4.在 Activity 中持有 WindowManager,便于在 Activity 中使用 WindowManager。
mWindowManager = mWindow.getWindowManager();
// ...省略代码...
}
Window
// Window.class
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated;
if (wm == null) {
/*
* 1.如果传入的 WindowManager 为空,就从服务里面获取。
* 注:
* Context.WINDOW_SERVICE = "window"。
* getSystemService()真正的执行逻辑在ContextImpl中。
* context.getSystemService(Context.WINDOW_SERVICE) 获取到的是 WindowManagerImpl 实例对象。
*/
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
// 2.这里会创建一个WindowManagerImpl对象。
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
ContextImpl
// ContextImpl.class
public Object getSystemService(String name) {
// 获取名字为 "window" 的服务
return SystemServiceRegistry.getSystemService(this, name);
}
SystemServiceRegistry
// SystemServiceRegistry.class
final class SystemServiceRegistry {
// 根据服务类型,保存服务名称
static Map<Class<?>, String> SYSTEM_SERVICE_NAMES = new ArrayMap<Class<?>, String>();
// 根据服务名称,获取实际的服务
static Map<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS = new ArrayMap<String, ServiceFetcher<?>>();
static {
// ...省略一系列的服务注册代码...
registerService(Context.WINDOW_SERVICE, WindowManager.class, new CachedServiceFetcher<WindowManager>() {
@Override
public WindowManager createService(ContextImpl ctx) {
// 实际获取到的是 WindowManagerImpl 实例对象,注意这的构造参数没有关联Window,在createLocalWindowManager过程中会与此处有关联。
return new WindowManagerImpl(ctx);
}});
}
// 根据服务名称来获取服务
public static Object getSystemService(ContextImpl ctx, String name) {
//
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
// 注册服务时,将服务保存在两个 Map 集合中。
private static <T> void registerService(String serviceName, Class<T> serviceClass,
ServiceFetcher<T> serviceFetcher) {
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
}
WindowManagerImpl
// WindowManagerImpl.class
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
小结:
问: 在执行
((WindowManagerImpl)wm).createLocalWindowManager(this)
方法时,参数wm
已经是 WindowManagerImpl 对象了,为什么还要通过 createLocalWindowManager() 重新创建一个 WindowManagerImpl 对象呢?
.
答: wm 对象内部没有关联当前的 Window,而重新创建的 WindowManagerImpl 对象会将当前的 Window 作为参数传入,因此新的 WindowManagerImpl 对象可以对 Window 进行操作。
2.3 WindowManagerImpl 类
public final class WindowManagerImpl implements WindowManager {
// 单例
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
// 添加默认token
applyDefaultToken(params);
// WindowManagerImpl 类相当于 WindowManagerGlobal 的代理。
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
}
三、Window 的属性 (类型和显示次序)
Window 的类型有很多种,总的来说分为三大类型,分别是 Application Window(应用程序窗口)
、Sub Window (子窗口)
、 System Window (系统窗口)
。
窗口类型 | Type 值 |
---|---|
应用程序窗口 | 1 ~ 99 |
子窗口 | 1000 ~ 1999 |
系统窗口 | 2000 ~ 2999 |
在一般情况下, Type 值越大则 Z-Oder 排序越靠前,就越靠近用户。
四、Window 的操作
我们知道,系统对 Window 进行添加、更新、删除操作,都是通过 WindowManager
来操作的。WindowManager 对 Window 的操作最后都交给 WindowManagerGlobal
来执行。
下面我们来分析一下 WindowManagerGlobal 是如何进行 Window 的添加、更新、删除操作的。
1. Window 的添加过程
时序图:
代码流程分析:
WindowManagerImpl
// WindowManagerImpl.class
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
WindowManagerGlobal
// WindowManagerGlobal.class
ArrayList<View> mViews = new ArrayList<View>();
ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>();
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
// ...省略代码...
// 1.根节点的LayoutParams必须为WindowManager.LayoutParams类型,因为确定根View的大小需要使用。
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
// 2.如果这个窗口有父窗口,则需要调整 wparams 的大小,使 wparams 的大小不超过父容器的大小。
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
// ...省略代码...
}
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
// ...省略代码...
// 3.将传入的根View添加到ViewRootImpl对象中(一个根View 对应一个 ViewRootImpl)。
root = new ViewRootImpl(view.getContext(), display);
// 4.将调整后的 wparams 赋值给根 View。
view.setLayoutParams(wparams);
// 5.将根 View、根View对应的ViewRootImpl、根View的布局参数LayoutParams分别存入三个集合中。
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
try {
// 6.执行 ViewRootImpl.setView() 方法。
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// ...省略代码...
}
}
}
ViewRootImpl
ViewRootImpl 类的主要职责:
- View 树的根并管理 View 树。
- 触发 View 的测量、 布局和绘制。
- 输入事件的中转站 。
- 管理 Surface 。
- 负责与 WMS 进行进程间通信 。
// ViewRootImpl.class
// 用于远程通信的Binder
IWindowSession mWindowSession = WindowManagerGlobal.getWindowSession();
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
// ...省略代码...
// 1.调用requestLayout方法进行绘制。
requestLayout();
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
// 2.获取远程服务进行通信(IWindowSession对象的获取在第4部分分析)
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
mTempInsets);
setFrame(mTmpFrame);
} catch (RemoteException e) {
// ...省略代码...
}
// ...省略代码...
}
}
}
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
// 该方法的分析过程请看本文 “scheduleTraversals() 执行流程” 部分。
scheduleTraversals();
}
}
从代码中我们可以看到,在 setView() 方法中,会调用 mWindowSession.addToDisplay()
来与远程服务进行通信 (mWindowSession 是一个 Binder 对象)。那 mWindowSession 对象又是如何获取的呢?这个在 Window 操作 - IWindowSession 对象的获取流程
分析。
Session
// Session.class
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState) {
// mService 就是 WMS,这里在操作 WMS.addView()过程中,将Session也传递进去,目的告诉WMS要操作哪个应用。
// 每个应用都对应一个唯一的Session,系统服务就是通过Session来区分不同的应用的。
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,
outInsetsState);
}
WindowManagerService
// WindowManagerService.class
public int addWindow(Session session, IWindow client, int seq,
LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState) {
// ...省略代码...
}
到这里,Window 在应用进程的添加逻辑就已经分析完了,在 WMS 部分的逻辑将在 WMS 分析中介绍。
2. Window 的更新过程
WindowManagerImpl
// WindowManagerImpl.class
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.updateViewLayout(view, params);
}
WindowManagerGlobal
// WindowManagerGlobal.class
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
// 1.校验 LayoutParams 类型
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
// 将 LayoutParams 添加到根 View 中。
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
view.setLayoutParams(wparams);
synchronized (mLock) {
// 3.替换 View 相关的参数(添加 View 时将 View,ViewRootImpl,LayoutParams 添加到三个集合中)
int index = findViewLocked(view, true);
ViewRootImpl root = mRoots.get(index);
mParams.remove(index);
mParams.add(index, wparams);
// 这里调用 ViewRootImpl.setLayoutParams 进行更新
root.setLayoutParams(wparams, false);
}
}
// 查询指定 View 在 mViews 集合中的位置。
private int findViewLocked(View view, boolean required) {
final int index = mViews.indexOf(view);
if (required && index < 0) {
throw new IllegalArgumentException("View=" + view + " not attached to window manager");
}
return index;
}
ViewRootImpl
// ViewRootImpl.class
void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
synchronized (this) {
// ...省略代码...
// 这里的操作与 Window 的添加过程一样。
scheduleTraversals();
}
}
到这里,Window 在应用进程的更新逻辑就已经分析完了,在 WMS 部分的逻辑将在 WMS 分析中介绍。
3. Window 的删除过程
WindowManagerImpl
// WindowManagerImpl.class
public void removeView(View view) {
mGlobal.removeView(view, false);
}
WindowManagerGlobal
public void removeView(View view, boolean immediate) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
synchronized (mLock) {
int index = findViewLocked(view, true);
View curView = mRoots.get(index).getView();
removeViewLocked(index, immediate);
if (curView == view) {
return;
}
throw new IllegalStateException("Calling with view " + view
+ " but the ViewAncestor is attached to " + curView);
}
}
private void removeViewLocked(int index, boolean immediate) {
ViewRootImpl root = mRoots.get(index);
View view = root.getView();
if (view != null) {
InputMethodManager imm = view.getContext().getSystemService(InputMethodManager.class);
if (imm != null) {
imm.windowDismissed(mViews.get(index).getWindowToken());
}
}
// 这里执行了 ViewRootImpl.die() 逻辑。
boolean deferred = root.die(immediate);
if (view != null) {
view.assignParent(null);
if (deferred) {
mDyingViews.add(view);
}
}
}
ViewRootImpl
// ViewRootImpl.class
boolean die(boolean immediate) {
// Make sure we do execute immediately if we are in the middle of a traversal or the damage
// done by dispatchDetachedFromWindow will cause havoc on return.
if (immediate && !mIsInTraversal) {
doDie();
return false;
}
// ...省略代码...
// 这里使用Handler发消息,其实也是调用了 doDie() 方法。
mHandler.sendEmptyMessage(MSG_DIE);
return true;
}
void doDie() {
// ...省略代码...
synchronized (this) {
// 使用 mRemoved 标记位,防止进行重复移除。
if (mRemoved) {
return;
}
mRemoved = true;
if (mAdded) {
// 1.将 View 从 Window 中移除。
dispatchDetachedFromWindow();
}
if (mAdded && !mFirst) {
destroyHardwareRenderer();
if (mView != null) {
int viewVisibility = mView.getVisibility();
boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
if (mWindowAttributesChanged || viewVisibilityChanged) {
// If layout params have been changed, first give them
// to the window manager to make sure it has the correct
// animation info.
try {
// 2.这个方法内部会与 WMS 进行通信。
if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
& WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
// 3.通过 IWindowSession 与 WMS 通信。
mWindowSession.finishDrawing(mWindow);
}
} catch (RemoteException e) {
}
}
// 4.释放 Surface 资源。
destroySurface();
}
}
mAdded = false;
}
// 5.将 ViewRootImpl 从 WindowManagerGlobal 中移除。
WindowManagerGlobal.getInstance().doRemoveView(this);
}
void dispatchDetachedFromWindow() {
// ...省略代码...
try {
// 通过 IWindowSession 调用远程 WMS 移除 Window。
mWindowSession.remove(mWindow);
}
// ...省略代码...
unscheduleTraversals();
}
void unscheduleTraversals() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
// 这一段代码与 Choreographer.postCallback() 方法类似(参考本文 "scheduleTraversals 执行流程" 部分的分析)。
mChoreographer.removeCallbacks(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
WindowManagerGlobal
void doRemoveView(ViewRootImpl root) {
synchronized (mLock) {
final int index = mRoots.indexOf(root);
if (index >= 0) {
// 移除 root 相关的信息。
mRoots.remove(index);
mParams.remove(index);
final View view = mViews.remove(index);
mDyingViews.remove(view);
}
}
if (ThreadedRenderer.sTrimForeground && ThreadedRenderer.isAvailable()) {
doTrimForeground();
}
}
到这里,Window 在应用进程的移除逻辑就已经分析完了,在 WMS 部分的逻辑将在 WMS 分析中介绍。
4. IWindowSession 对象的获取流程
IWindowSession 是一个 Binder 对象,用于进行进程间通信。IWindowSession 是 Client 端的代理 (运行在应用进程),它的 Server端的实现为 Session (运行在 WMS 所在进程)。
时序图:
代码流程分析:
// WindowManagerGlobal.class
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
// 1.获取 WMS 远程代理。
IWindowManager windowManager = getWindowManagerService();
// 2.通过远程代理类获取WindowSession远程代理。
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
});
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
// WindowManagerGlobal.class
public static IWindowManager getWindowManagerService() {
synchronized (WindowManagerGlobal.class) {
if (sWindowManagerService == null) {
// 通过AIDL方式获取 WMS 的远程代理(WMS是在SystemServer.startOtherServices()中启动的)。
sWindowManagerService = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
// ...省略代码...
}
return sWindowManagerService;
}
}
// WindowManagerService.class
public IWindowSession openSession(IWindowSessionCallback callback) {
return new Session(this, callback);
}
// Session.class
public Session(WindowManagerService service, IWindowSessionCallback callback) {
mService = service;
mCallback = callback;
// ...省略代码...
// 构建一个Session,每个应用都对应一个唯一的Session,系统服务就是通过Session来区分不同的应用的。
StringBuilder sb = new StringBuilder();
sb.append("Session{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(" ");
sb.append(mPid);
if (mUid < Process.FIRST_APPLICATION_UID) {
sb.append(":");
sb.append(mUid);
} else {
sb.append(":u");
sb.append(UserHandle.getUserId(mUid));
sb.append('a');
sb.append(UserHandle.getAppId(mUid));
}
sb.append("}");
mStringName = sb.toString();
try {
mCallback.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) {
// The caller has died, so we can just forget about this.
// Hmmm, should we call killSessionLocked()??
}
}
Session 的作用: 每个应用都对应一个唯一的Session,系统服务就是通过Session来区分不同的应用的。
5. ViewRootImpl.scheduleTraversals() 执行流程
方法调用流程: scheduleTraversals() --> TraversalRunnable.run() --> doTraversal() --> performTraversals()
在 performTraversals()
方法中,会触发 View 的 measure、layout、draw 三个过程,如下图所示 (图片来源于网络):
代码流程分析:
ViewRootImpl
// ViewRootImpl.class
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// postCallback 添加回调,这个添加的回调将在下一帧被渲染时执行。
// Choreographer 用了接收显示系统的 VSync 信号。
mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
final class TraversalRunnable implements Runnable {
@Override
public void run() {
// 执行操作
doTraversal();
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
// 执行操作
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
public final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
private void performTraversals() {
// ...省略代码...
WindowManager.LayoutParams lp = mWindowAttributes;
// ...省略代码...
if (mFirst || windowShouldResize || insetsChanged ||
viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
// ...省略代码...
try {
// ...省略代码...
// 1.触发 WMS 的 Window 更新操作。
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
// ...省略代码...
}
if (!mStopped || mReportNextDraw) {
if (条件判断) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
// ...省略代码...
// 2.从根 View 开始测量操作
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
// ...省略代码...
// 如果WindowManager.LayoutParams有权重,需进行二次测量。
boolean measureAgain = false;
// ...省略代码...
if (measureAgain) {
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
}
layoutRequested = true;
}
}
}
// ...省略代码...
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
if (didLayout) {
// 3.从根 View 开始计算 View 的位置。
performLayout(lp, mWidth, mHeight);
// ...省略代码...
}
// ...省略代码...
boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
if (!cancelDraw) {
// ...省略代码...
// 4.从根 View 开始绘制 View。
performDraw();
} else {
// ...省略代码...
}
mIsInTraversal = false;
}
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
// ...省略代码...
// 通过 IWindowSession 与远程服务进行通信。
int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
mTmpFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
mPendingMergedConfiguration, mSurfaceControl, mTempInsets);
// ...省略代码...
return relayoutResult;
}
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
// ...省略代码...
// mView 是 DecorView,从根 View 开始测量 View 的大小。
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
int desiredWindowHeight) {
// ...省略代码...
final View host = mView;
// host 是 DecorView,从根 View 开始计算 View 的位置。
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
// ...省略代码...
}
private void performDraw() {
// ...省略代码...
try {
boolean canUseAsync = draw(fullRedrawNeeded);
// ...省略代码...
}
// ...省略代码...
}
private boolean draw(boolean fullRedrawNeeded) {
Surface surface = mSurface;
// ...省略代码...
if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
if (条件判断) {
// ...省略代码...
} else {
// ...省略代码...
// 执行 View 的绘制逻辑。
if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
scalingRequired, dirty, surfaceInsets)) {
return false;
}
}
}
// ...省略代码...
return useAsyncReport;
}
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
// Draw with software renderer.
final Canvas canvas;
// ...省略代码...
try {
// ...省略代码...
// 1.从 Surface 中获取画布,其实真正的视图是渲染在 Surface 上的。
canvas = mSurface.lockCanvas(dirty);
// TODO: Do this in native
canvas.setDensity(mDensity);
}
// ...省略代码...
try {
// ...省略代码...
// 2.mView是 DecorView,从根 View 开始绘制。
mView.draw(canvas);
drawAccessibilityFocusedDrawableIfNeeded(canvas);
}
// ...省略代码...
return true;
}
小结:
- 在
performTraversals()
方法中,会触发 View 的measure、layout、draw
三个过程。 relayoutWindow()
方法会触发 WMS 的 Window 操作。
五、不同类型窗口的操作
Window 的类型主要分为三种:Application Window(应用程序窗口)
、Sub Window (子窗口)
、 System Window (系统窗口)
。而不同的窗口类型,它的操作流程也有一些不同。下面分析一下系统窗口和应用窗口的添加过程。
1. 系统窗口的添加过程
我们以 StatusBar 为例来分析系统窗口的添加过程。
// com.android.systemui.statusbar.phone.StatusBar.class
// 这是将 StatusBar 添加到 Window 的方法
public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {
// 1.创建一个 StatusBarView
makeStatusBarView(result);
// Dependency.get() 的操作和前面的 mContext.getSystemService(Context.WINDOW_SERVICE) 有点类似,
// 都是预先在一个服务里面注册,然后在使用的地方通过指定类型来获取的。
mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
// 2.将 StatusBar 和它的高度值传给 StatusBarWindowController控制器(MVC模式)
mStatusBarWindowController.add(mStatusBarWindow, getStatusBarHeight());
}
StatusBarWindowController
// StatusBarWindowController.class
public void add(ViewGroup statusBarView, int barHeight) {
// 1.创建一个窗口的 LayoutParams 参数
mLp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
barHeight, //指定的高度值
WindowManager.LayoutParams.TYPE_STATUS_BAR, //这里指定窗口的类型为StatusBar
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
PixelFormat.TRANSLUCENT);
mLp.token = new Binder();
mLp.gravity = Gravity.TOP;
mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
mLp.setTitle("StatusBar");
mLp.packageName = mContext.getPackageName();
mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
mStatusBarView = statusBarView;
mBarHeight = barHeight;
// 2.将创建的StatusBar 通过 WindowManager添加到 Window 中。
mWindowManager.addView(mStatusBarView, mLp);
mLpChanged.copyFrom(mLp);
onThemeChanged();
}
代码中第2步,调用 WindowManager.addView()
方法来添加系统的 Window,这个过程在上面已经分析过了,此处不再赘述。
2. Activity 的添加过程
在应用程序中,Activity 是最为常见,我们以 Activity 为例来分析应用窗口的添加过程。
当界面要与用户进行交互时,会调用 ActivityThread. handleResumeActivity()
方法。
ActivityThread
// ActivityThread.class
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) {
// ...省略代码...
// TODO Push resumeArgs into the activity for consideration
// 1.将 Activity 回复到 RESUME 状态。
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
// ...省略代码...
final Activity a = r.activity;
// ...省略代码...
if (r.window == null && !a.mFinished && willBeVisible) {
// 2.获取在 Activity.attach() 方法中就创建了 PhoneWindow 对象。
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
// 这里使 Decor 不可见。
decor.setVisibility(View.INVISIBLE);
// 3.获取 Activity 中持有的 WindowManager。
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
//将 Activity.WindowAdded 标记为true,避免在 Activity.makeVisible() 是重复进行 Window 添加操作。
a.mWindowAdded = true;
// 将根 View(DecorView)通过 WindowManager 添加到 Window 中。
wm.addView(decor, l);
} else {
a.onWindowAttributesChanged(l);
}
}
}
// ...省略代码...
// The window is now visible if it has been added, we are not
// simply finishing, and we are not starting another activity.
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
// ...省略代码...
r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
// 这个方法内部会是 DecorView 可见。
r.activity.makeVisible();
}
}
}
public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest, String reason) {
// 1.每一个 ActivityClientRecord 都代表着一个 Activity 。
final ActivityClientRecord r = mActivities.get(token);
// ...省略代码...
try {
r.activity.onStateNotSaved();
r.activity.mFragments.noteStateNotSaved();
checkAndBlockForNetworkAccess();
if (r.pendingIntents != null) {
// 这里会触发 Activity.onNewIntent()方法。
deliverNewIntents(r, r.pendingIntents);
r.pendingIntents = null;
}
if (r.pendingResults != null) {
// 这里会触发 Activity.onActivityResult()方法。
deliverResults(r, r.pendingResults, reason);
r.pendingResults = null;
}
// 这里会触发 Activity.onResume()方法。
r.activity.performResume(r.startsNotResumed, reason);
r.state = null;
r.persistentState = null;
// 这里将当前 Activity 的生命周期状态设置为 ON_RESUME。
r.setState(ON_RESUME);
reportTopResumedActivityChanged(r, r.isTopResumedActivity, "topWhenResuming");
} catch (Exception e) {
// ...省略代码...
}
return r;
}
Activity
// Activity.class
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
// 将 DecorView设置为可见。
mDecor.setVisibility(View.VISIBLE);
}
在 Activity 执行 Resume 生命周期时,也会触发 Window 的添加操作。