Window的删除过程
上篇文章我们讲到了Window的添加过程,接下来我们来分析Window的删除过程。还是和添加一样,首先通过WindowManagerImpl这个对象调用removeView方法。
@Override
public void removeView(View view) {
mGlobal.removeView(view, false);
}
接着通过 WindowManagerGlobal mGlobal 对象调用removeView方法。我们来看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);
}
}
我们来看核心实现,首先从mViews集合获取需要删除View的索引,因为在添加View的时候,把View添加到了mViews这个集合。
int index = findViewLocked(view, true);
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;
}
通过索引调用removeViewLocked方法,删除该View
removeViewLocked(index, immediate);
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);
}
}
}
我们看上面的源码。首先通过该View对应的索引,获取对应的ViewRootImpl类,我们知道每个Window和View多是通过ViewRootImpl建立连接的,对Window的操作,其实就是通过ViewRootImpl来操作的。每个Window都会有对应的ViewRootImpl类。拿到该View对应的ViewRootImpl也就是该Window对应的ViewRootImpl类之后,调用die方法进行删除操作。
boolean deferred = root.die(immediate);
我们来看下die方法的实现,
/**
* @param immediate True, do now if not in traversal. False, put on queue and do later.
* @return True, request has been queued. False, request has been completed.
*/
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(mTag, "Attempting to destroy the window while drawing!\n" +
" window=" + this + ", title=" + mWindowAttributes.getTitle());
}
mHandler.sendEmptyMessage(MSG_DIE);
return true;
}
在这个方法中,有一个immediate参数,表示异步删除还是同步删除,如果是同步删除,直接调用doDie()方法。如果是异步删除,发送一个消息 mHandler.sendEmptyMessage(MSG_DIE);然后调用doDiew()方法。因此,删除的核心方法都在doDie()中。我们来看下doDie()方法的实现
void doDie() {
checkThread();
if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
synchronized (this) {
if (mRemoved) {
return;
}
mRemoved = true;
if (mAdded) {
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 {
if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
& WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
mWindowSession.finishDrawing(mWindow);
}
} catch (RemoteException e) {
}
}
mSurface.release();
}
}
mAdded = false;
}
WindowManagerGlobal.getInstance().doRemoveView(this);
}
在doDie()方法中,删除的核心实现通过 dispatchDetachedFromWindow();来完成。
void dispatchDetachedFromWindow() {
if (mView != null && mView.mAttachInfo != null) {
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
mView.dispatchDetachedFromWindow();
}
mAccessibilityInteractionConnectionManager.ensureNoConnection();
mAccessibilityManager.removeAccessibilityStateChangeListener(
mAccessibilityInteractionConnectionManager);
mAccessibilityManager.removeHighTextContrastStateChangeListener(
mHighContrastTextManager);
removeSendWindowContentChangedCallback();
destroyHardwareRenderer();
setAccessibilityFocus(null, null);
mView.assignParent(null);
mView = null;
mAttachInfo.mRootView = null;
mSurface.release();
if (mInputQueueCallback != null && mInputQueue != null) {
mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
mInputQueue.dispose();
mInputQueueCallback = null;
mInputQueue = null;
}
if (mInputEventReceiver != null) {
mInputEventReceiver.dispose();
mInputEventReceiver = null;
}
try {
mWindowSession.remove(mWindow);
} catch (RemoteException e) {
}
// Dispose the input channel after removing the window so the Window Manager
// doesn't interpret the input channel being closed as an abnormal termination.
if (mInputChannel != null) {
mInputChannel.dispose();
mInputChannel = null;
}
mDisplayManager.unregisterDisplayListener(mDisplayListener);
unscheduleTraversals();
}
在dispatchDetachedFromWindow方法中主要完成以下这些操作。
(1)调用View的dispatchDetachedFromWindow();方法,做一些资源回收的工作,比如终止动画,停止线程等。
(2)垃圾回收,比如清楚数据和消息,移除回调
(3)第三点比较重要,也是实现删除Window的真正实现, mWindowSession.remove(mWindow);在上篇文章我们知道,mWindowSession是一个Binder对象,这里是一个IPC机制,通过跨进程通信,把删除Window的操作交给了WindowManagerService进行删除。
(4)调用 WindowManagerGlobal.getInstance().doRemoveView(this);把当前保存的删除的View 列表进行移除刷新。
以上就是Window的删除大概的流程,我们做下小结:
我们知道删除Window
1.首先交给WindowManagerGlobal 的removie方法,这个方法是为了拿到需要删除的View的索引,再通过该索引拿到对应的ViewRootImpl对象,
2.然后删除Window的实现交给了ViewRootImpl来完成。通过调用die方法。
3.最后的核心删除操作就是和添加Window类似,通过Binde对象mWindowSession实现跨进程通信,把最终的删除操作交给了WindowManagerService完成,删除完成之后,再对一些垃圾的回收,数据的清除,回调的移除,以及删除列表的更新。
Window的更新过程
我们上面分别介绍了Window的添加以及删除过程,下面我们来介绍,Window的更新过程。
还是一样首先从WindowImpl的updateViewLayout
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.updateViewLayout(view, params);
}
网友评论