Window是一個(gè)抽象的概念,每一個(gè)Window都對(duì)應(yīng)一個(gè)View和一個(gè)ViewRootImpl,Window和View通過ViewRootImpl來建立聯(lián)系。
在實(shí)際使用中無法直接訪問Window,對(duì)Window的訪問必須通過Windowmanager。
Window實(shí)際上是View的直接管理者
Android中所有的視圖都是通過Window來呈現(xiàn)的,不管是Activity、Dialog還是Toast,它們的視圖實(shí)際上是附加在Window上的。對(duì)應(yīng)著一個(gè)Activity
子Window不能單獨(dú)存在,它需要附屬在特定的父Window之中,比如Dialog
需要聲明權(quán)限才能創(chuàng)建的Window,比如Toast和系統(tǒng)狀態(tài)欄
層級(jí)大的Window會(huì)覆蓋層級(jí)小的Window,層級(jí)對(duì)應(yīng)于WindowManager.LayoutParams的type參數(shù)。
應(yīng)用Window層級(jí)范圍:1~999 子Window的層級(jí)范圍:1000~1999 系統(tǒng)Window的層級(jí)范圍:2000~2999
Window通過WindowManager來訪問,WindowManager是一個(gè)接口,它的真正實(shí)現(xiàn)是WindowManagerImpl。而WindowmanagerImpl的增刪更新View都交由WindowManagerGlobal來處理。
public final class WindowManagerImpl implements WindowManager { PRivate final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); @Override public void addView(View view, ViewGroup.LayoutParams params) { mGlobal.addView(view, params, mDisplay, mParentWindow); } @Override public void updateViewLayout(View view, ViewGroup.LayoutParams params) { mGlobal.updateViewLayout(view, params); } @Override public void removeView(View view) { mGlobal.removeView(view, false); }}需要了解的WindowManagerGlobal的幾個(gè)重要的參數(shù)
//存儲(chǔ)所有Window所對(duì)應(yīng)的Viewprivate final ArrayList<View> mViews = new ArrayList<View>();//存儲(chǔ)所有Window所對(duì)應(yīng)的ViewRootImplprivate final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();//存儲(chǔ)所有Window所對(duì)應(yīng)的布局參數(shù)private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>();//存儲(chǔ)即將被刪除的View對(duì)象 (已經(jīng)調(diào)用removeView方法但是刪除操作還未完成的Window對(duì)象)private final ArraySet<View> mDyingViews = new ArraySet<View>();Window的添加過程通過WindowManager的addView來實(shí)現(xiàn)
WindowManagerGlobal的addView()
在來看ViewRootImpl#setView(),Window的添加請(qǐng)求最終交給WindowManagerService處理。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { //... //[重要方法] requestLayout-> ... -> performTraversals -> 開始measure、layout、draw三大流程 requestLayout(); //... try { //通過Windowsession最終完成Window的添加 //mWindowSession是IWindowSession,它是一個(gè)Binder對(duì)象 [ipC調(diào)用] //mWindowSession.addToDisplay -> WindowmanagerService.addWindow mOrigWindowType = mWindowAttributes.type; mAttachInfo.mRecomputeGlobalAttributes = true; collectViewAttributes(); res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mInputChannel); } catch (RemoteException e) { mAdded = false; mView = null; mAttachInfo.mRootView = null; mInputChannel = null; mFallbackEventHandler.setView(null); unscheduleTraversals(); setaccessibilityFocus(null, null); throw new RuntimeException("Adding window failed", e); } //...}再來看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); } }}再來看die方法。如果是同步刪除,立即調(diào)用doDie(),如果是異步調(diào)用,會(huì)通過Handler發(fā)送消息調(diào)用doDie()。
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. //立即刪除 -> 同步刪除 (不推薦,容易發(fā)生意外) 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;}再來看doDie()
void doDie() { //... //真正刪除View dispatchDetachedFromWindow(); //...}dispatchDetachedFromWindow主要做4件事
垃圾回收相關(guān)的工作,比如清除數(shù)據(jù)和消息,移除回調(diào)。 通過Session的remove方法刪除Window:mWindowSession.remove(mWindow),這同樣是一個(gè)IPC過程,最終會(huì)調(diào)用WindowManagerService的removeWindow方法。 調(diào)用View的dispatchDetachedFromWindow方法,在內(nèi)部會(huì)調(diào)用View的onDetachedFromWindow()以及onDetachedFromWindowInternal()。調(diào)用WindowManagerGlobal的doRemoveView方法刷新數(shù)據(jù),包括mRoots、mParams以及mDyingViews,需要將當(dāng)前Window所關(guān)聯(lián)的這三個(gè)對(duì)象從列表中刪除。onDetachedFromWindow() 當(dāng)View從Window中移除時(shí),這個(gè)方法就會(huì)被調(diào)用。 可以在這個(gè)方法內(nèi)部做一個(gè)資源回收工作,比如終止動(dòng)畫、停止線程。
window的更新通過WindowManagerGlobal#updateViewLayout()來完成,內(nèi)部通過調(diào)用VIewRootImpl的setLayoutParams(),然后經(jīng)過一些列的方法,最終會(huì)開始measure、layout、draw三大流程,從而實(shí)現(xiàn)window的更新。
參考 《Android藝術(shù)開發(fā)探索》
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注