一、前言
Window的刪除過程,本文中從WindowManagerImpl開始講起,主要做了四個事情如圖右所示。
WMS刪除窗口.png
二、源碼分析
1、刪除窗口視圖
public final class ActivityThread extends ClientTransactionHandler {
@Override
public void handleDestroyActivity(IBinder token, boolean finishing, int configChanges,
boolean getNonConfigInstance, String reason) {
//最終執行Activity的onDestroy()
ActivityClientRecord r = performDestroyActivity(token, finishing,
configChanges, getNonConfigInstance, reason);
if (r != null) {
cleanUpPendingRemoveWindows(r, finishing);
WindowManager wm = r.activity.getWindowManager();
View v = r.activity.mDecor;
if (v != null) {
if (r.activity.mVisibleFromServer) {
mNumVisibleActivities--;
}
IBinder wtoken = v.getWindowToken();
if (r.activity.mWindowAdded) {
if (r.mPreserveWindow) {
r.mPendingRemoveWindow = r.window;
r.mPendingRemoveWindowManager = wm;
r.window.clearContentView();
} else {
//進入WindowManagerImpl進行移除相關操作
wm.removeViewImmediate(v);
}
}
if (wtoken != null && r.mPendingRemoveWindow == null) {
WindowManagerGlobal.getInstance().closeAll(wtoken,
r.activity.getClass().getName(), "Activity");
} else if (r.mPendingRemoveWindow != null) {
WindowManagerGlobal.getInstance().closeAllExceptView(token, v,
r.activity.getClass().getName(), "Activity");
}
r.activity.mDecor = null;
}
if (r.mPendingRemoveWindow == null) {
WindowManagerGlobal.getInstance().closeAll(token,
r.activity.getClass().getName(), "Activity");
}
Context c = r.activity.getBaseContext();
if (c instanceof ContextImpl) {
((ContextImpl) c).scheduleFinalCleanup(
r.activity.getClass().getName(), "Activity");
}
}
if (finishing) {
try {
ActivityTaskManager.getService().activityDestroyed(token);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
mSomeActivitiesChanged = true;
}
}
- 進入
WindowManagerImpl
,因為WindowManager繼承ViewManager,所以WindowManagerImpl 才有相關的添加,刪除和更新操作。
public final class WindowManagerImpl implements WindowManager {
@Override
public void removeView(View view) {
mGlobal.removeView(view, false);
}
//立即移除
@Override
public void removeViewImmediate(View view) {
mGlobal.removeView(view, true);
}
}
- 進入
WindowManagerGlobal
public final class WindowManagerGlobal {
//要銷毀試圖集合,存放的是DecorView
private final ArraySet<View> mDyingViews = new ArraySet<View>();
public void removeView(View view, boolean immediate) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
synchronized (mLock) {
//獲取 View 在集合中的位置
int index = findViewLocked(view, true);
//獲取ViewRootImpl中的DecorView
View curView = mRoots.get(index).getView();
removeViewLocked(index, immediate);
if (curView == view) { //刪除的是DecorView 直接返回,否則拋出異常
return;
}
throw new IllegalStateException("Calling with view " + view
+ " but the ViewAncestor is attached to " + curView);
}
}
//獲取刪除View在mView集合中的索引
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;
}
private void removeViewLocked(int index, boolean immediate) {
ViewRootImpl root = mRoots.get(index);
View view = root.getView();//DecorView
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);
}
}
}
}
2、判斷是否立即執行刪除
在ViewRootImpl
中die
方法中,會先判斷是否立即執行刪除,如果被判處死刑且立即執行則調用doDie方法,如果不是則通過Handler方法執行死刑的信號,判個緩刑。
boolean die(boolean immediate) {.
//immediate 是否立即執行 為ture則立即執行刪除
if (immediate && !mIsInTraversal) {
doDie();
return false;
}
......
//通過Handler發送死亡信息,判處死緩
//最終執行到 doDie() 方法
mHandler.sendEmptyMessage(MSG_DIE);
return true;
}
void doDie() {
//檢查線程
checkThread();
if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
synchronized (this) {
//判斷是否刪除
if (mRemoved) {
return;
}
//防止重復調用
mRemoved = true;
if (mAdded) {
//做數據清除 注銷操作,調用session的remove方法
dispatchDetachedFromWindow();
}
if (mAdded && !mFirst) {
destroyHardwareRenderer();
if (mView != null) {
int viewVisibility = mView.getVisibility();
boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
if (mWindowAttributesChanged || viewVisibilityChanged) {
try {
if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
& WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
mWindowSession.finishDrawing(
mWindow, null /* postDrawTransaction */);
}
} catch (RemoteException e) {
}
}
//銷毀畫布
destroySurface();
}
}
mAdded = false;
}
//調用WindowManagerGlobal移除方法
WindowManagerGlobal.getInstance().doRemoveView(this);
}
-
ViewRootImpl@checkThread()
檢查線程的正確性
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
在ViewRootImpl的dispatchDetachedFromWindow
方法中會調用 Session 與WMS進行通信,然后執行移除的操作。
void dispatchDetachedFromWindow() {
mFirstInputStage.onDetachedFromWindow();
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; //DecorView
mAttachInfo.mRootView = null;
mSurface.release(); //銷毀Surface.
if (mInputQueueCallback != null && mInputQueue != null) {
mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
mInputQueue.dispose();
mInputQueueCallback = null;
mInputQueue = null;
}
if (mInputEventReceiver != null) {
mInputEventReceiver.dispose();
mInputEventReceiver = null;
}
try {// 通過IWindowSession 關聯到 WMS中刪除信息
mWindowSession.remove(mWindow);
} catch (RemoteException e) {
}
if (mInputChannel != null) {
mInputChannel.dispose();
mInputChannel = null;
}
mDisplayManager.unregisterDisplayListener(mDisplayListener);
unscheduleTraversals();
}
在WMS
的removeWindow
函數中,先會通過Session和Client獲取到當前窗口在WMS的副本也就是WindowState,如果不為空則執行刪除操作。
會進入 Session@remove
方法,Session
時 IWindowSession
的實現類
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
final WindowManagerService mService;
@Override
public void remove(IWindow window) {
mService.removeWindow(this, window);
}
}
- 進入到
WindowManagerService@removeWindow
方法
//每個WMS都有一個唯一的 Session
void removeWindow(Session session, IWindow client) {
synchronized (mGlobalLock) {
//獲取WindowState
WindowState win = windowForClientLocked(session, client, false);
if (win != null) {
//執行刪除
win.removeIfPossible();
return;
}
mEmbeddedWindowController.remove(client);
}
}
- 從WMS中獲取
WindowState
final HashMap<IBinder, WindowState> mWindowMap = new HashMap<>();
final WindowState windowForClientLocked(Session session, IWindow client, boolean throwOnError) {
return windowForClientLocked(session, client.asBinder(), throwOnError);
}
final WindowState windowForClientLocked(Session session, IBinder client, boolean throwOnError) {
WindowState win = mWindowMap.get(client);
if (DEBUG) Slog.v(TAG_WM, "Looking up client " + client + ": " + win);
if (win == null) {
if (throwOnError) {
throw new IllegalArgumentException(
"Requested window " + client + " does not exist");
}
ProtoLog.w(WM_ERROR, "Failed looking up window session=%s callers=%s", session,
Debug.getCallers(3));
return null;
}
if (session != null && win.mSession != session) {
if (throwOnError) {
throw new IllegalArgumentException("Requested window " + client + " is in session "
+ win.mSession + ", not " + session);
}
ProtoLog.w(WM_ERROR, "Failed looking up window session=%s callers=%s", session,
Debug.getCallers(3));
return null;
}
return win;
}
- 重置和刪除
WindowState
狀態
win.removeIfPossible
方法和它的名字一樣,并不是直接執行刪除操作,而是進行多個條件判斷過濾,滿足其中一個條件就會return,推遲刪除操作。比如View正在運行一個動畫,這是就會推遲刪除操作知道動畫完成。然后調用removeImmediately
方法。
class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState,
InsetsControlTarget {
void removeImmediately() {
super.removeImmediately();
//已經刪除
if (mRemoved) {
// Nothing to do.
ProtoLog.v(WM_DEBUG_ADD_REMOVE,
"WS.removeImmediately: %s Already removed...", this);
return;
}
//移除標記
mRemoved = true;
......
final DisplayContent dc = getDisplayContent();
......
//policy做移除操作
dc.getDisplayPolicy().removeWindowLw(this);
//關閉輸入事件渠道
disposeInputChannel();
mWinAnimator.destroyDeferredSurfaceLocked();
mWinAnimator.destroySurfaceLocked();
//Session集合沖移除WindowState
mSession.windowRemovedLocked();
.....
//集中處理清除工作
mWmService.postWindowRemoveCleanupLocked(this);
}
}
3、WindowManagerGlobal 相關數據刪除
在WindowManagerGlobal方法中,會刪除相關的一些數據,如ViewRootImpl、LayoutParams、DecorView,并將DecorView加入到死亡列表中。
WindowManagerGlobal@doRemoveView(...)
void doRemoveView(ViewRootImpl root) {
boolean allViewsRemoved;
synchronized (mLock) {
//從ViewRootImpl獲取到索引值
final int index = mRoots.indexOf(root);
if (index >= 0) {
//刪除ViewRootImpl列表中的數據
mRoots.remove(index);
//刪除LayoutParams列表中的數據
mParams.remove(index);
//刪除DecorView列表中的數據
final View view = mViews.remove(index);
//DecorView加入到死亡列表
mDyingViews.remove(view);
}
allViewsRemoved = mRoots.isEmpty();
}
if (ThreadedRenderer.sTrimForeground && ThreadedRenderer.isAvailable()) {
doTrimForeground();
}
if (allViewsRemoved) {
InsetsAnimationThread.release();
}
}