窗口布局简介
在安卓的窗口管理系统中,经常要执行的一个操作是布局。
布局会做许多事情,例如更新焦点窗口、调整所有的窗口位置、设置wallpaperTarget以显示或隐藏壁纸、开始过渡动画等。
很多时候都需要进行窗口的布局,例如View的Surface创建流程中调用WindowManagerService的relayoutWindow方法时、窗口创建时、窗口销毁时、窗口可见性变化时等。
布局流程
窗口布局流程一般从frameworks/base/services/core/java/com/android/server/wm/WindowSurfacePlacer.java的performSurfacePlacement方法开始:
final void performSurfacePlacement() {
performSurfacePlacement(false /* force */);
}
final void performSurfacePlacement(boolean force) {
if (mDeferDepth > 0 && !force) {
mDeferredRequests++;
return;
}
int loopCount = 6;
do {
mTraversalScheduled = false;
performSurfacePlacementLoop();
mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
loopCount--;
} while (mTraversalScheduled && loopCount > 0);
mService.mRoot.mWallpaperActionPending = false;
}
这里有一个循环,循环限制了最多循环6次。可以发现在窗口布局时,不能确保一次完成布局,可能会重复布局多次。这里循环体内主要是调用了WindowSurfacePlacer的performSurfacePlacementLoop方法:
private void performSurfacePlacementLoop() {
if (mInLayout) {
if (DEBUG) {
throw new RuntimeException("Recursive call!");
}
Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
+ Debug.getCallers(3));
return;
}
// TODO(multi-display):
final DisplayContent defaultDisplay = mService.getDefaultDisplayContentLocked();
if (defaultDisplay.mWaitingForConfig) {
// Our configuration has changed (most likely rotation), but we
// don't yet have the complete configuration to report to
// applications. Don't do any window layout until we have it.
return;
}
if (!mService.mDisplayReady) {
// Not yet initialized, nothing to do.
return;
}
mInLayout = true;
if (!mService.mForceRemoves.isEmpty()) {
// Wait a little bit for things to settle down, and off we go.
while (!mService.mForceRemoves.isEmpty()) {
final WindowState ws = mService.mForceRemoves.remove(0);
Slog.i(TAG, "Force removing: " + ws);
ws.removeImmediately();
}
Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
Object tmp = new Object();
synchronized (tmp) {
try {
tmp.wait(250);
} catch (InterruptedException e) {
}
}
}
try {
mService.mRoot.performSurfacePlacement();
mInLayout = false