🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
#### 8.2.2 Window的删除过程 Window的删除过程和添加过程一样,都是先通过WindowManagerImpl后,再进一步通过WindowManagerGlobal来实现的。下面是WindowManagerGlobal的removeView的实现: 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); } } removeView的逻辑很清晰,首先通过findViewLocked来查找待删除的View的索引,这个查找过程就是建立的数组遍历,然后再调用removeViewLocked来做进一步的删除,如下所示。 private void removeViewLocked(int index, boolean immediate) { ViewRootImpl root = mRoots.get(index); View view = root.getView(); if (view ! = null) { InputMethodManager imm = InputMethodManager.getInstance(); if (imm ! = null) { imm.windowDismissed(mViews.get(index).getWindowToken()); } } boolean deferred = root.die(immediate); if (view ! = null) { view.assignParent(null); if (deferred) { mDyingViews.add(view); } } } removeViewLocked是通过ViewRootImpl来完成删除操作的。在WindowManager中提供了两种删除接口removeView和removeViewImmediate,它们分别表示异步删除和同步删除,其中removeViewImmediate使用起来需要特别注意,一般来说不需要使用此方法来删除Window以免发生意外的错误。这里主要说异步删除的情况,具体的删除操作由ViewRoot-Impl的die方法来完成。在异步删除的情况下,die方法只是发送了一个请求删除的消息后就立刻返回了,这个时候View并没有完成删除操作,所以最后会将其添加到mDyingViews中,mDyingViews表示待删除的View列表。ViewRootImpl的die方法如下所示。 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; } if (! mIsDrawing) { destroyHardwareRenderer(); } else { Log.e(TAG, "Attempting to destroy the window while drawing! \n" + " window=" + this + ", title=" + mWindowAttributes. getTitle()); } mHandler.sendEmptyMessage(MSG_DIE); return true; } 在die方法内部只是做了简单的判断,如果是异步删除,那么就发送一个MSG_DIE的消息,ViewRootImpl中的Handler会处理此消息并调用doDie方法,如果是同步删除(立即删除),那么就不发消息直接调用doDie方法,这就是这两种删除方式的区别。在doDie内部会调用dispatchDetachedFromWindow方法,真正删除View的逻辑在dispatchDetachedFromWindow方法的内部实现。dispatchDetachedFromWindow方法主要做四件事: * (1)垃圾回收相关的工作,比如清除数据和消息、移除回调。 * (2)通过Session的remove方法删除Window:mWindowSession.remove(mWindow),这同样是一个IPC过程,最终会调用WindowManagerService的removeWindow方法。 * (3)调用View的dispatchDetachedFromWindow方法,在内部会调用View的onDetached-FromWindow()以及onDetachedFromWindowInternal()。对于onDetachedFromWindow()大家一定不陌生,当View从Window中移除时,这个方法就会被调用,可以在这个方法内部做一些资源回收的工作,比如终止动画、停止线程等。 * (4)调用WindowManagerGlobal的doRemoveView方法刷新数据,包括mRoots、mParams以及mDyingViews,需要将当前Window所关联的这三类对象从列表中删除。