上篇文章已經分析了Window的建立過程,這篇文章繼續分析Window的删除過程,WindowManager調用removeView(View view)方法,最終執行的是其實作類WindowMangerImpl的removeView(View view)方法下面看看WindowManagerImpl的removeView方法的源碼:
/frameworks/base/core/java/android/view/WindowManagerImpl.java
http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/view/WindowManagerImpl.java
@Override
public void removeView(View view) {
mGlobal.removeView(view, false);
}
可以看到這個方法的移除view的操作是委托給了WindowManagerGlobal的removeView()方法來完成的。下面來看看
WindowManagerGlobal的removeView方法的源碼:
/frameworks/base/core/java/android/view/WindowManagerGlobal.java
http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/view/WindowManagerGlobal.java
public void removeView(View view, boolean immediate) {
//... 省略部分代碼
synchronized (mLock) {
int index = findViewLocked(view, true);
View curView = mRoots.get(index).getView();
// 關鍵代碼
removeViewLocked(index, immediate);
//... 省略部分代碼
}
}
private void removeViewLocked(int index, boolean immediate) {
ViewRootImpl root = mRoots.get(index);
View view = root.getView();
//... 省略部分代碼
//關鍵代碼
boolean deferred = root.die(immediate);
if (view != null) {
view.assignParent(null);
if (deferred) {
// 關鍵代碼
mDyingViews.add(view);
}
}
}
removeViewLocked方法中,調用了ViewRootImpl的die方法,下面看看這個方法的源碼:
/frameworks/base/core/java/android/view/ViewRootImpl.java
http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/view/ViewRootImpl.java
boolean die(boolean immediate) {
if (immediate && !mIsInTraversal) {
// 1 關鍵代碼
doDie();
return false;
}
// ... 省略部分代碼
// 2 關鍵代碼
mHandler.sendEmptyMessage(MSG_DIE);
return true;
}
// doDie方法的具體實作
void doDie() {
checkThread();
synchronized (this) {
if (mRemoved) {
return;
}
mRemoved = true;
if (mAdded) {
//關鍵代碼
dispatchDetachedFromWindow();
}
// ... 省略部分代碼
}
// 關鍵代碼
WindowManagerGlobal.getInstance().doRemoveView(this);
}
上面的die方法中如果傳入的immediate參數為true,則表示立即(同步)删除,如果傳入的immediate是false,則會通過
mHandler.sendEmptyMessage(MSG_DIE);進行異步删除。下面先看看立即(同步)删除的邏輯,上面的doDie方法又調用到了dispatchDetachedFromWindow();方法,下面看看這個方法的實作:
/frameworks/base/core/java/android/view/ViewRootImpl.java
http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/view/ViewRootImpl.java
void dispatchDetachedFromWindow() {
mFirstInputStage.onDetachedFromWindow();
if (mView != null && mView.mAttachInfo != null) {
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
mView.dispatchDetachedFromWindow();
}
// ... 省略部分代碼
try {
// 關鍵代碼 ,這裡通過IPC和WindowManagerService進行通信,SystemServer程序中,
// 調用Session的remove方法
// 最終還是調用了WindowManagerService的removeWindow方法,将window移除。
mWindowSession.remove(mWindow);
} catch (RemoteException e) {
}
// ... 省略部分代碼
}
這個方法内部其實是通過WindowManagerService在用戶端的代理對象mWindowSession調用remove方法移除window,
這個方法調用會向SystemServer程序發起通信,調用Session類的remove方法,下面看看這個方法的具體實作:
/frameworks/base/services/core/java/com/android/server/wm/Session.java
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/wm/Session.java
@Override
public void remove(IWindow window) {
mService.removeWindow(this, window);
}
這個方法内部最終還是調用了WindowManagerService的removeWindow方法,将window移除。這個步驟是完成了SystemServer程序中移除Window的操作,接着在app程序,我們要将WindowManagerGlobal類中儲存的關于window的各種相關的參數都清除。下面看看WindowManagerGlobal的doRemoveView()方法,下面看看這個方法的源碼:
/frameworks/base/core/java/android/view/WindowManagerGlobal.java
http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/view/WindowManagerGlobal.java
void doRemoveView(ViewRootImpl root) {
synchronized (mLock) {
final int index = mRoots.indexOf(root);
if (index >= 0) {
mRoots.remove(index);
mParams.remove(index);
final View view = mViews.remove(index);
mDyingViews.remove(view);
}
}
if (ThreadedRenderer.sTrimForeground && ThreadedRenderer.isAvailable()) {
doTrimForeground();
}
}
這個方法内部,其實就是将WindowManagerGlobal内部,存儲Window的view的相關資訊的幾個集合中,和這個window
相關的資訊都移除掉。
接着在看看異步删除view的邏輯:
ViewRootImpl類内部是有一個ViewRootHandler類型的handler的
final ViewRootHandler mHandler = new ViewRootHandler();
final class ViewRootHandler extends Handler {
// ... 省略部分代碼
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
// ... 省略部分代碼
case MSG_DIE:
//關鍵代碼
doDie();
break;
// ... 省略部分代碼
}
}
}
在handler内部收到MSG_DIE這個消息後,調用了ViewRootImpl類的doDie()方法進行window的移除操作。doDie方法的内部實作,上面以及貼出。