Android Framework-WMS-Window移除

昨天和基友装逼,结果人说你这半拉子,只写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,进入到WMSremoveWindow

调用removeIfPossible()

如果没有动画,则直接调用removeImmediately()。 会调用WindowStateAnimator.destroySurfaceLocked() 进行surface的清理,清理WindowState。 调用父类WindowContainer.removeImmediately() 清理surface ,从父亲删除自己,通知自己被移除。

如果有动画,会等待动画完成后,调用到 removeImmediately()。进行对应的清理和回收。

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

相关推荐
小趴菜82275 小时前
Android TabLayout使用记录
android
梦终剧5 小时前
【Android之路】 Kotlin 的 data class、enum class、sealed interface
android·开发语言·kotlin
折翅鵬14 小时前
Android 程序员如何系统学习 MQTT
android·学习
搬砖的小码农_Sky14 小时前
如何将安卓应用迁移到鸿蒙?
android·华为·harmonyos
搬砖的小码农_Sky14 小时前
鸿蒙应用开发和安卓应用开发的区别
android·华为·harmonyos
2501_9160074714 小时前
iOS 混淆与团队协作,研发、安全、运维、测试如何在加固流程中高效配合(iOS 混淆、ipa 加固、协作治理)
android·ios·小程序·https·uni-app·iphone·webview
飞猿_SIR16 小时前
基于海思Hi3798MV200Android7.0聊聊HDMI色深模式和电视HDR
android·嵌入式硬件·音视频
come1123417 小时前
ptyhon 基础语法学习(对比php)
android·学习
ClassOps17 小时前
Android 12 SplashScreen启动屏
android·kotlin