国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

Window和WindowManager

2019-11-09 18:37:51
字體:
供稿:網(wǎng)友

Window和WindowManager

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上的。

Window的類型

應(yīng)用Window

對(duì)應(yīng)著一個(gè)Activity

子Window

子Window不能單獨(dú)存在,它需要附屬在特定的父Window之中,比如Dialog

系統(tǒng)Window

需要聲明權(quán)限才能創(chuàng)建的Window,比如Toast和系統(tǒng)狀態(tài)欄

Window的層級(jí)

層級(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

WindowManger

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的添加過程

Window的添加過程通過WindowManager的addView來實(shí)現(xiàn)

WindowManagerGlobal的addView()

1.檢查參數(shù)是否合法,如果是子Window那么還需要調(diào)整一些布局參數(shù)

if (view == null) { throw new IllegalArgumentException("view must not be null");}if (display == null) { throw new IllegalArgumentException("display must not be null");}if (!(params instanceof WindowManager.LayoutParams)) { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");}final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;if (parentWindow != null) { parentWindow.adjustLayoutParamsForSubWindow(wparams);}

2.創(chuàng)建ViewRootImpl并將View添加到列表中

root = new ViewRootImpl(view.getContext(), display);view.setLayoutParams(wparams);mViews.add(view);mRoots.add(root);mParams.add(wparams);

3.通過ViewRootImpl來更新界面并完成window的添加過程

//setView->requestLayout-> ... -> performTraversals -> 開始measure、layout、draw三大流程root.setView(view, wparams, panelParentView);

在來看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); } //...}

WIndow的刪除過程

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(); //通過index查找待刪除的View removeViewLocked(index, immediate); if (curView == view) { return; } throw new IllegalStateException("Calling with view " + view + " but the ViewAncestor is attached to " + curView); }}

再來看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的更新過程

public void updateViewLayout(View view, ViewGroup.LayoutParams params) { if (view == null) { throw new IllegalArgumentException("view must not be null"); } if (!(params instanceof WindowManager.LayoutParams)) { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); } final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params; view.setLayoutParams(wparams); synchronized (mLock) { int index = findViewLocked(view, true); ViewRootImpl root = mRoots.get(index); mParams.remove(index); mParams.add(index, wparams); //更新LayoutParams -> scheduleTraversals -> ... -> 開始measure、layout、draw三大流程 root.setLayoutParams(wparams, false); }}

window的更新通過WindowManagerGlobal#updateViewLayout()來完成,內(nèi)部通過調(diào)用VIewRootImpl的setLayoutParams(),然后經(jīng)過一些列的方法,最終會(huì)開始measure、layout、draw三大流程,從而實(shí)現(xiàn)window的更新。

其他

參考 《Android藝術(shù)開發(fā)探索》


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 成安县| 汾阳市| 菏泽市| 嘉黎县| 福州市| 成都市| 陇川县| 宝山区| 垫江县| 正镶白旗| 武威市| 万州区| 图片| 天等县| 大厂| 文昌市| 普兰县| 大田县| 横峰县| 太和县| 庆安县| 开阳县| 册亨县| 双桥区| 调兵山市| 通州市| 湟中县| 镇巴县| 贡山| 石阡县| 阳城县| 武山县| 宁明县| 天津市| 宜宾县| 中宁县| 苍溪县| 宁陵县| 益阳市| 汶川县| 天门市|