
昨天和基友装逼,结果人说你这半拉子,只写addWindow()
,removeWindow(
) 你是一点不写啊。 抓紧补充一下。 主要我之前也没看过这部分,面试没人问啊。
大体流程
java
ViewRootImpl.doDie(){
dispatchDetachedFromWindow();
}
-->mWindowSession.remove(mWindow);
-->Session.remove()
-->WindowManagerService.removeWindow(this, window);
-->WindowState.removeIfPossible();
这里主要看一下WindowState.removeIfPossible()
java
private void removeIfPossible(boolean keepVisibleDeadWindow) {
mWindowRemovalAllowed = true;
//是启动窗口 去取消动画
final boolean startingWindow = mAttrs.type == TYPE_APPLICATION_STARTING;
if (startingWindow)
if (mActivityRecord != null) {
mActivityRecord.forAllWindows(w -> {
if (w.isSelfAnimating(0, ANIMATION_TYPE_STARTING_REVEAL)) {
w.cancelAnimation();
return true;
}
return false;
}, true);
}
} else if (mAttrs.type == TYPE_BASE_APPLICATION
&& isSelfAnimating(0, ANIMATION_TYPE_STARTING_REVEAL)) {
//是应用类型 取消动画
cancelAnimation();
}
final DisplayContent displayContent = getDisplayContent();
final long origId = Binder.clearCallingIdentity();
try {
//取消事件
disposeInputChannel();
mOnBackInvokedCallbackInfo = null;
boolean wasVisible = false;
if (mHasSurface && mToken.okToAnimate()) {
if (mWillReplaceWindow) {
mAnimatingExit = true;
mReplacingRemoveRequested = true;
return;
}
wasVisible = isWinVisibleLw();
//标记死亡
if (keepVisibleDeadWindow) {
mAppDied = true;
setDisplayLayoutNeeded();
mWmService.mWindowPlacerLocked.performSurfacePlacement();
openInputChannel(null);
displayContent.getInputMonitor().updateInputWindowsLw(true);
return;
}
final boolean allowExitAnimation = !displayContent.inTransition()
&& !inRelaunchingActivity();
if (wasVisible) {
final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE;
if (allowExitAnimation && mWinAnimator.applyAnimationLocked(transit, false)) {
mAnimatingExit = true;
setDisplayLayoutNeeded();
mWmService.requestTraversal();
}
if (mWmService.mAccessibilityController.hasCallbacks()) {
mWmService.mAccessibilityController.onWindowTransition(this, transit);
}
}
final boolean isAnimating = allowExitAnimation
&& (mAnimatingExit || isExitAnimationRunningSelfOrParent());
final boolean lastWindowIsStartingWindow = startingWindow && mActivityRecord != null
&& mActivityRecord.isLastWindow(this);
//看是否有动画或者正在执行退出动画 完成后进行移除
if (mWinAnimator.getShown() && !lastWindowIsStartingWindow && isAnimating) {
mAnimatingExit = true;
//
setupWindowForRemoveOnExit();
if (mActivityRecord != null) {
mActivityRecord.updateReportedVisibilityLocked();
}
return;
}
}
final boolean windowProvidesNonDecorInsets = providesNonDecorInsets();
//直接移除
removeImmediately();
boolean needToSendNewConfiguration = wasVisible && displayContent.updateOrientation();
if (windowProvidesNonDecorInsets) {
needToSendNewConfiguration |=
displayContent.getDisplayPolicy().updateDecorInsetsInfo();
}
if (needToSendNewConfiguration) {
displayContent.sendNewConfiguration();
}
//更新焦点。
mWmService.updateFocusedWindowLocked(isFocused()
? UPDATE_FOCUS_REMOVING_FOCUS
: UPDATE_FOCUS_NORMAL,
true /*updateInputWindows*/);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
这里分2种情况,有动画的需要等待动画执行完成,没动画的直接调用了removeImmediately()
直接删除
removeImmediately()
java
//WindowState
void removeImmediately() {
//销毁surface
mWinAnimator.destroySurfaceLocked(getSyncTransaction());
//调用到父类 进入
super.removeImmediately();
//省略..
//断开输入
disposeInputChannel();
//告知Session 该窗口已经删除
mSession.windowRemovedLocked();
//wms进行各种清除,主要是各种缓存,简单理解观察者模式删除观察者
mWmService.postWindowRemoveCleanupLocked(this);
}
该方法主要是进行各种销毁,内部调用到了WindowStateAnimator.destroySurfaceLocked()
和super.removeImmediately()
进入了 WindowContainer.removeImmediately()
先看下 WindowStateAnimator.destroySurfaceLocked()
java
void destroySurfaceLocked(SurfaceControl.Transaction t) {
if (mSurfaceController == null) {
return;
}
mWin.mHidden = true;
try {
destroySurface(t);
mWallpaperControllerLocked.hideWallpapers(mWin);
} catch (RuntimeException e) {
}
mWin.setHasSurface(false);
if (mSurfaceController != null) {
mSurfaceController.setShown(false);
}
mSurfaceController = null;
mDrawState = NO_SURFACE;
}
WindowStateAnimator.destroySurfaceLocked()
主要是销毁 surface
,然后将状态设置到 NO_SURFACE
状态, mSurfaceController
也设置了 null
, 标识当前 WindowState
不存在 surface
,有点类似Message
的 obtain()
,把属性都清空了。
再看下WindowContainer.removeImmediately()
java
void removeImmediately() {
final DisplayContent dc = getDisplayContent();
if (dc != null) {
dc.mClosingChangingContainers.remove(this);
mSurfaceFreezer.unfreeze(getSyncTransaction());
}
while (!mChildren.isEmpty()) {
final E child = mChildren.peekLast();
child.removeImmediately();
if (mChildren.remove(child)) {
onChildRemoved(child);
}
}
if (mSurfaceControl != null) {
getSyncTransaction().remove(mSurfaceControl);
setSurfaceControl(null);
mLastSurfacePosition.set(0, 0);
mLastDeltaRotation = Surface.ROTATION_0;
scheduleAnimation();
}
if (mOverlayHost != null) {
mOverlayHost.release();
mOverlayHost = null;
}
if (mParent != null) {
mParent.removeChild(this);
}
for (int i = mListeners.size() - 1; i >= 0; --i) {
mListeners.get(i).onRemoved();
}
}
移除当前窗口,删除子窗口,从父亲那删除自己,清理surface
,调用mListeners
通知自己已经被移除。
有动画的时候
# Android Framework-WMS-动画-初步认识中,动画完成后会调用onAnimationFinished
java
WindowContainer(WindowManagerService wms) {
mWmService = wms;
mTransitionController = mWmService.mAtmService.getTransitionController();
mPendingTransaction = wms.mTransactionFactory.get();
mSyncTransaction = wms.mTransactionFactory.get();
mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, wms);
mSurfaceFreezer = new SurfaceFreezer(this, wms);
}
*/
protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
doAnimationFinished(type, anim);
mWmService.onAnimationFinished();
mNeedsZBoost = false;
}
这里会进入子类 WindowState
java
@Override
protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
super.onAnimationFinished(type, anim);
mWinAnimator.onAnimationFinished();
}
调用 WindowStateAnimator.onAnimationFinished()
,继续调用到 WindowState.onExitAnimationDone()
java
//WindowState
void onExitAnimationDone() {
//省略///
//注意该值设置为trye
mDestroying = true;
final boolean hasSurface = mWinAnimator.hasSurface();
//hide
mWinAnimator.hide(getPendingTransaction(), "onExitAnimationDone");
if (mActivityRecord != null) {
//如果是app 进入ActivityRecord的destroySurfaces
if (mAttrs.type == TYPE_BASE_APPLICATION) {
mActivityRecord.destroySurfaces();
} else {
destroySurface(false /* cleanupOnResume */, mActivityRecord.mAppStopped);
}
} else {
if (hasSurface) {
//
mWmService.mDestroySurface.add(this);
}
}
mAnimatingExit = false;
getDisplayContent().mWallpaperController.hideWallpapers(this);
}
destroySurface()
有两个判断 分别在onExitAnimationDone(
)和setupWindowForRemoveOnExit()
里面被设置为了true。
java
boolean destroySurface(boolean cleanupOnResume, boolean appStopped) {
boolean destroyedSomething = false;
//在调用 onExitAnimationDone的时候 设置为true
if (mDestroying) {
//省略
// 在 setupWindowForRemoveOnExit()里面设置为true
if (mRemoveOnExit) {
removeImmediately();
}
mDestroying = false;
destroyedSomething = true;
//省略
}
return destroyedSomething;
}
发现进入removeImmediately()
走到了无动画删除的流程。
总结一下
window
的删除 从ViewRootImp
通过Session
,进入到WMS
的removeWindow
。
调用removeIfPossible()
。
如果没有动画,则直接调用removeImmediately()
。 会调用WindowStateAnimator.destroySurfaceLocked()
进行surface
的清理,清理WindowState
。 调用父类WindowContainer.removeImmediately()
清理surface
,从父亲删除自己,通知自己被移除。
如果有动画,会等待动画完成后,调用到 removeImmediately()
。进行对应的清理和回收。

不要死记代码,主要我记不住。