前言
Window
表示一個(gè)窗口的概念虏束,Android
中所有的視圖都是通過Window
來呈現(xiàn)的洪添,不管是Activity
绅项、Dialog
、還是Toast
赋续,它們的視圖實(shí)際上都是附加在Window
上的男翰,因此,Window
實(shí)際是View
的管理者纽乱。Window
是一個(gè)非常重要的子系統(tǒng)奏篙,這也是我們常說的WMS
(WindowManagerService
)。下面我們就分析一下Window
迫淹、WMS
、View
建立關(guān)聯(lián)以及交互的一個(gè)基本過程为严。
Window體系相關(guān)UML類圖
-
Session :是一個(gè)
Binder
對(duì)象敛熬,代表一個(gè)活躍的客戶端會(huì)話,在每個(gè)進(jìn)程中都有一個(gè)
Session 與WindowManager交互的對(duì)象第股。 -
WindowManagerService :也是一個(gè)
Binder
對(duì)象应民,負(fù)責(zé)對(duì)窗口的管理。 - Window :應(yīng)用程序用來與窗口管理器交談的界面夕吻。
- PhoneWindow :Window 的具體實(shí)現(xiàn)诲锹。
- WindowManagerImpl : 負(fù)責(zé)與系統(tǒng)窗口管理器通信、綁定到上下文涉馅、顯示的操作归园。
- ViewRootImpl :負(fù)責(zé)View的(測(cè)量、擺放稚矿、繪制)三大流程庸诱。
- WindowManagerGlobal :WindowManager 的具體實(shí)現(xiàn)捻浦。
WindowManager
與WindowManager
聯(lián)系上的第一步就是通過Context
的getSystemService
()方法,在分析文章Android源碼中單例模式 中我們知道桥爽,各種系統(tǒng)服務(wù)會(huì)注冊(cè)到ContextImpl
的一個(gè)map
容器中朱灿,然后通過該服務(wù)的字符串鍵獲取,WindowManager
也是ContextImpl
中注冊(cè)的眾多服務(wù)之一钠四,我們看下下面這段程序:
//窗口服務(wù)
registerService(Context.WINDOW_SERVICE, WindowManager.class,
new CachedServiceFetcher<WindowManager>() {
@Override
public WindowManager createService(ContextImpl ctx) {
return new WindowManagerImpl(ctx);
}});
最后一行代碼中盗扒,我們看到了WindowManager
在Java層的具體實(shí)現(xiàn),也就是WindowManagerImpl
缀去。那Activity
或者Dialog
又是如何獲取到WindowManager
對(duì)象呢侣灶?我們從上述代碼知道,WindowManager
是注冊(cè)到ContextImpl
中的朵耕,而getSystemService
也是Context
定義的接口炫隶,因此,我們就從Dialog的構(gòu)造函數(shù)和Activity入手阎曹,因?yàn)?code>Context是傳到Dialog
構(gòu)造函數(shù)的伪阶。
Dialog構(gòu)造函數(shù)
Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
//獲取WindowManager
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
final Window w = new PhoneWindow(mContext);
mWindow = w;
//設(shè)置Window回調(diào)
w.setCallback(this);
w.setOnWindowDismissedCallback(this);
w.setOnWindowSwipeDismissedCallback(() -> {
if (mCancelable) {
cancel();
}
});
//設(shè)置Window的WindowManager對(duì)象
w.setWindowManager(mWindowManager, null, null);
w.setGravity(Gravity.CENTER);
}
Activity的attch方法
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
...
//創(chuàng)建Window并設(shè)置window的監(jiān)聽
mWindow = new PhoneWindow(this, window);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
...
//Window設(shè)置WindowManager對(duì)象
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
無論是Dialog
還是Activity
都是通過Window
對(duì)象的setWindowManager
方法將WindowManager
與Window
關(guān)聯(lián)。該函數(shù)是在Window
中处嫌,看看實(shí)現(xiàn):
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
...
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
最后調(diào)用的是WindowManagerImpl
的createLocalWindowManager
方法栅贴,這里與ContextImpl
注冊(cè)的WindowManagerImpl
不同的是,這里多了一個(gè)parentWindow
參數(shù)熏迹,也就是說檐薯,此時(shí)構(gòu)建的WindowManagerImpl
對(duì)象是與具體的Window
關(guān)聯(lián)的,而ContextImpl
注冊(cè)的并沒有此參數(shù)注暗。這是Window
已經(jīng)和WindowManager
建立了初步聯(lián)系坛缕。為什么這么說呢?我們看下WindowManagerImpl
的具體實(shí)現(xiàn):
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
private final Context mContext;
private final Window mParentWindow;
...
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.updateViewLayout(view, params);
}
@Override
public void removeView(View view) {
mGlobal.removeView(view, false);
}
@Override
public void removeViewImmediate(View view) {
mGlobal.removeView(view, true);
}
@Override
public Display getDefaultDisplay() {
return mContext.getDisplay();
}
}
顯然WindowManagerImpl
還沒有實(shí)現(xiàn)對(duì)視圖的操作捆昏,Dialog是在show()方法里添加的赚楚,添加、更新骗卜、刪除都交給了WindowManagerGlobal
這個(gè)類宠页,通過以上分析對(duì)VIew
的操作實(shí)際上是調(diào)用的是WindowManagerGlobal
的方法,繼續(xù)跟蹤:
WindowManagerGlobal對(duì)View的操作
看上面UML類圖我看到WindowManagerGlobal有幾個(gè)重要的屬性寇仓,
private final ArrayList<View> mViews = new ArrayList<View>();
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
private final ArrayList<WindowManager.LayoutParams> mParams =
new ArrayList<WindowManager.LayoutParams>();
private final ArraySet<View> mDyingViews = new ArraySet<View>();
在上面聲明中举户,沒mViews
存儲(chǔ)的是所有Window
所對(duì)應(yīng)的View
,mRoots
存儲(chǔ)的是所有Window
多對(duì)用的ContextImpl
,mParams
存儲(chǔ)的是所有Window
的布局參數(shù)遍烦,而mDyingViews
則存儲(chǔ)了那些整被刪除的View
對(duì)象俭嘁,或者說那些已經(jīng)調(diào)用removeView
方法但是刪除操作還未完成的Window
對(duì)象,在addView
中將Window
一系列對(duì)象添加到容器中乳愉。
WindowManagerGlobal的addView過程
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...//省略參數(shù)檢查代碼
ViewRootImpl root;
View panelParentView = null;
...
//創(chuàng)建ViewRootImpl
root = new ViewRootImpl(view.getContext(), display);
//設(shè)置參數(shù)
view.setLayoutParams(wparams);
//添加到容器列表中
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
}
// 調(diào)用ViewRootImpl的setView方法將VIew顯示到手機(jī)上
root.setView(view, wparams, panelParentView);
}
上面程序主要完成以下工作;
- 構(gòu)建ViewRootImpl兄淫;
- 將布局參數(shù)設(shè)置給View屯远;
- 存儲(chǔ)這些ViewRootImpl、View捕虽、LayoutParam到列表中慨丐;
- 通過ViewRootImpl的setView將View顯示到窗口。
很多人對(duì)ViewRootImpl
并不陌生泄私,從UML類圖可以看出這個(gè)類里面有一個(gè)我們熟知的performTraversals
方法房揭,ViewRootImpl
收到系統(tǒng)繪制View的消息后performTraversals
就會(huì)調(diào)用視圖樹的各個(gè)節(jié)點(diǎn)的meature
、layout
晌端、draw
方法來繪制整顆視圖樹捅暴。
從上述代碼分析來看,第一個(gè)重要步驟就是創(chuàng)建了ViewRootImpl
對(duì)象咧纠,我們看看它的構(gòu)造方法:
public ViewRootImpl(Context context, Display display) {
mContext = context;
//獲取Window Session蓬痒,也就是也WindowManagerService建立聯(lián)系
mWindowSession = WindowManagerGlobal.getWindowSession();
//保存當(dāng)前線程,漆羔,更新Ui的 線程只能是創(chuàng)建ViewRootImpl時(shí)的線程梧奢,
//我們?cè)陂_發(fā)中,如果在子線程更新UI會(huì)拋出異常演痒,但并不是因?yàn)橹挥蠻I線程才能更新UI
//而是因?yàn)閂iewRootImpl是在UI線程中創(chuàng)建的
mThread = Thread.currentThread();
...
}
獲取WindowManagerService
我們看下ViewRootImpl
的構(gòu)造函數(shù)中是如何獲取到WindowManagerService
的:
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
InputMethodManager imm = InputMethodManager.getInstance();
//獲取WindowManagerService
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(
imm.getClient(), imm.getInputContext());
}
return sWindowSession;
}
}
//獲取WindowManagerService
public static IWindowManager getWindowManagerService() {
synchronized (WindowManagerGlobal.class) {
if (sWindowManagerService == null) {
//aidl
sWindowManagerService = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
}
return sWindowManagerService;
}
}
在getWindowSession
方法中亲轨,FrameWork
層首先通過getWindowManagerService
方法獲取IWindowManager
對(duì)象,該函數(shù)中通過ServiceManager
.getService
方法獲取WMS
鸟顺,并且將WMS
轉(zhuǎn)換為IWindowManager
類型惦蚊,我們先看看ServiceManager
.getService
方法:
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return Binder.allowBlocking(getIServiceManager().getService(name));
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
從程序中可以看到ServiceManager.getService
返回的是一個(gè)IBinder
對(duì)象,也就是說Android Framework
層與WMS
之間也是通過Binder
機(jī)制進(jìn)行通訊讯嫂。獲取WMS
之后蹦锋,又調(diào)用IWindowManager
.Stub
類的asInterface
方法,看到這里我們就會(huì)想起AIDL
欧芽,詳情請(qǐng)看這篇文章理解AIDL 晕粪,將獲取到的WMS
的IBinder
對(duì)象轉(zhuǎn)換成WindowManager
對(duì)象,最后渐裸,通過openSession
函數(shù)來與WMS
建立一個(gè)通信會(huì)話,相當(dāng)于Framework
層與native
層建立了一個(gè)長(zhǎng)期合作的”辦事處“装悲,雙方有什么需求都通過這個(gè)Session
來交換信息昏鹃。
ViewRootImpl的setView方法
與WMS
建立Session
后就到了ViewRootImpl
的setView
方法了,該方法會(huì)向WMS
發(fā)起顯示Dialog
或者Activity
中的DecorView
請(qǐng)求诀诊,具體代碼:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
//請(qǐng)求布局
requestLayout();
//向WMS發(fā)起請(qǐng)求
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
}
}
}
setView
過程比較復(fù)雜洞渤,但我們只需要關(guān)注兩步:
- requestLayout();
- 向WMS發(fā)起顯示當(dāng)前Window請(qǐng)求
ViewRootImpl的requestLayout過程
我們?cè)賮砜聪?code>requestLayout方法
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
//發(fā)起繪制
scheduleTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//注意第二個(gè)參數(shù),第一個(gè)第三個(gè)省略
mChoreographer.postCallback(... , mTraversalRunnable , ... );
...
}
}
//創(chuàng)建子線程去繪制
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
void doTraversal() {
//繪制入口
performTraversals();
}
最終會(huì)執(zhí)行performTraversals
();方法属瓣,這是一個(gè)極其復(fù)雜有非常重要的函數(shù)载迄。主要做了如下操作:
- 獲取Surface對(duì)象讯柔,同于圖形繪制
- 測(cè)量視圖樹中各個(gè)View的大小,performMeasure()
- 擺放整個(gè)視圖樹,performLayout()
- 繪制整棵視圖樹,performDraw()
代碼如下:
private void performTraversals() {
//會(huì)調(diào)用View的onMeasure
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
//會(huì)調(diào)用View的onLayout
performLayout(lp, mWidth, mHeight);
//會(huì)調(diào)用View的Draw
performDraw();
}
在performDraw
方法中,Framework
層獲取到圖形繪制表面的Surface
對(duì)象护昧,然后獲取它的可繪制區(qū)域魂迄,也就是我們的Canvas
對(duì)象,然后Framework
在這個(gè)Canvas
對(duì)象上繪制惋耙,具體代碼如下;
private void performDraw() {
draw(fullRedrawNeeded);
}
private void draw(boolean fullRedrawNeeded) {
//獲取繪制表面
Surface surface = mSurface;
if (!surface.isValid()) {
return;
}
...
if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
//使用GPU繪制捣炬,也就是硬件加速
if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
...
mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
} else {
//使用CPU繪制圖形
if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
return;
}
}
}
}
在draw
方法中會(huì)獲取到需要繪制的區(qū)域,以及判斷是否使用GPU
進(jìn)行繪制绽榛。通常情況下使用的是CPU
繪制湿酸,也就是調(diào)用的是drawSoftware
()。我們看看該函數(shù)的實(shí)現(xiàn):
//使用CPU繪制
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty) {
// Draw with software renderer.
final Canvas canvas;
try {
//獲取指定區(qū)域的獲取指定區(qū)域的Canvas對(duì)象對(duì)象灭美,用于繪制
canvas = mSurface.lockCanvas(dirty);
}
...
try {
...
//從DecorView開始繪制推溃,也就是整個(gè)Window的根視圖,整棵樹都會(huì)繪制
mView.draw(canvas);
} finally {
try {
//釋放Canvas鎖届腐,然后通知Surface更新這塊區(qū)域铁坎,與開頭照應(yīng)
surface.unlockCanvasAndPost(canvas);
}
return true;
}
綜上所述,上述的視圖樹繪制代碼主要分為下面幾個(gè)步驟:
- 判斷是CPU還是GPU繪制
- 獲取繪制表面的Surface對(duì)象
- 通過Surface對(duì)象獲取并鎖住Canvas繪圖對(duì)象
- 從DecorView開始發(fā)起整顆樹的繪制流程
- Surface對(duì)象解鎖Canvas梯捕,并通知SurfaceFlinger更新視圖
了解具體View的三大流程請(qǐng)看文章:
以上就是整個(gè)視圖的繪制過程厢呵,但是此時(shí)Dialog
或者Activity
的View
并不能顯示在手機(jī)屏幕上,WMS
只是負(fù)責(zé)管理手機(jī)上的View
傀顾,也就是說WMS
管理當(dāng)前狀態(tài)下那個(gè)View
應(yīng)該顯示在最上層襟铭。其實(shí)WMS
管理的并不是Window
,而是View
短曾,只不過他管理的是屬于某個(gè)WIndow
下的View
寒砖。
ViewRootImpl請(qǐng)求WMS添加Window過程
我們上面只是分析了ViewRootImpl
的requestLayout
過程,下面再回到ViewRootImpl
的setView
方法嫉拐,繪制完成接著會(huì)通過WindowSession
最終來完成WIndow
的添加過程哩都,在下面的代碼中mWindowSession
的類型是IWindowSession
,它也是一個(gè)Binder
對(duì)象婉徘,真正的實(shí)現(xiàn)類是Session
漠嵌,也就是Window
的添加過程是一次IPC
調(diào)用。
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
在Session內(nèi)部會(huì)通過WindowManagerService
來實(shí)現(xiàn)Window
的添加盖呼,代碼如下:
frameworks\base\services\core\java\com\android\server\wm\Session.java
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
Rect outOutsets, InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}
這樣Window
的添加過程就交給了WindowManagerService
去處理了儒鹿,在WMS內(nèi)部會(huì)保留一個(gè)單獨(dú)的Session
。具體Window
在WMS
內(nèi)部如何添加的几晤,本篇不對(duì)分析约炎,至此對(duì)于View
的繪制以及視圖如何添加到Window
整個(gè)流程已經(jīng)很明了了。關(guān)于WMS
和Surface
系統(tǒng)的細(xì)節(jié)可以參考市面上關(guān)于源碼的書籍。我們看下Window
的刪除過程
WindowManagerGlobal的removeView過程
Window
的刪除過程和添加過程一樣圾浅,都是先通過WIndowManagerImpl
后掠手,在進(jìn)一步通過WindowManagerGlobal
來實(shí)現(xiàn)刪除,下面是WindowManagerGlobal
的removeView
的實(shí)現(xiàn):
public void removeView(View view, boolean immediate) {
...
synchronized (mLock) {
int index = findViewLocked(view, true);
View curView = mRoots.get(index).getView();
removeViewLocked(index, immediate);
}
...
}
removeView
的過程很清晰狸捕,首先通過findViewLoched
來查找待刪除View
的索引喷鸽,這個(gè)查找過程就是建立的數(shù)組遍歷,然后再調(diào)用removeViewLocked
來做進(jìn)一步的刪除府寒,如下所示:
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);
}
}
}
removeViewLocked
是通過ViewRootImpl
來完成刪除操作的魁衙。在WIndowManager
中提供了兩個(gè)接口removeView
和removeViewImmediate
,分別表示異步刪除和同步刪除株搔,一般不使用同步刪除剖淀,以免發(fā)生意外的錯(cuò)誤,這里主要說下異步刪除的情況纤房,具體的異步刪除操作是由ViewRootImpl
的die
方法完成纵隔,在異步刪除的情況下,die
方法只是發(fā)送了一個(gè)請(qǐng)求刪除的消息后就立刻返回了炮姨,這個(gè)時(shí)候View
并沒有完成刪除操作捌刮,所以最后會(huì)將其添加到WindowManagerGlobal
的待刪除列表mDyingViews
中,看下ViewRootImpl
的die
方法實(shí)現(xiàn):
boolean die(boolean immediate) {
//同步刪除 直接調(diào)用doDie舒岸,并返回
if (immediate && !mIsInTraversal) {
doDie();
return false;
}
...
//發(fā)送handler消息
mHandler.sendEmptyMessage(MSG_DIE);
return true;
}
在die方法內(nèi)部只是做了簡(jiǎn)單的判斷绅作,如果是異步刪除,那么就發(fā)送一個(gè)MSG_DIE 的消息蛾派,ViewRootImpl
中的Handler
會(huì)調(diào)用doDie
方法俄认,如果是同步刪除,就不發(fā)送消息洪乍,直接調(diào)用doDie
方法眯杏,這就是這兩種方法的區(qū)別。在doDie
方法中會(huì)調(diào)用dispatchDepatchedFromWindow
方法壳澳,真正刪除View
的邏輯在dispatchDepatchedFromWindow
內(nèi)部實(shí)現(xiàn)岂贩,代碼如下:
void doDie() {
dispatchDetachedFromWindow();
//將WindowManagerGlobal的列表中移除保存的ViewRootImpl、View巷波、Param
WindowManagerGlobal.getInstance().doRemoveView(this);
}
void dispatchDetachedFromWindow() {
//調(diào)用VIew的dispatchDetachedFromWindow();
mView.dispatchDetachedFromWindow();
...
//Session中的remove
mWindowSession.remove(mWindow);
...
}
public void remove(IWindow window) {
//WMS移除Window
mService.removeWindow(this, window);
}
//WindowManagerGlobal中移除保存的ViewRootImpl萎津、View、Param
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);
}
}
}
以上代碼主要做了一下事情:
- 垃圾回收相關(guān)的工作抹镊,比如清除數(shù)據(jù)和消息姜性,移除回調(diào)
- 通過Session的remove方法刪除Window,同樣也是一個(gè)IPC過程髓考,最終會(huì)調(diào)用WMS的removeView方法
- 調(diào)用View的dispatchDetachedFromWindow();方法,對(duì)于View的dispatchDetachedFromWindow()我們不陌生弃酌,當(dāng)View從Window中移除時(shí)氨菇,這個(gè)方法就會(huì)被調(diào)用儡炼,可以在這個(gè)方法內(nèi)部做一些資源回收的工作,比如終止動(dòng)畫查蓉、停止線程乌询。
- 調(diào)用WindowManagerGlobal的doRemoveView方法刷新數(shù)據(jù),包括mViews豌研、mRoots妹田、mParams、mDyingViews鹃共,需要將當(dāng)前Window所關(guān)聯(lián)的這三類對(duì)象從列表中刪除鬼佣。
WindowManagerGlobal的updateViewLayout過程
Window
的刪除過程我們已經(jīng)分析完了,下面看下WIndow
的更新過程霜浴,還是要從WindowManagerGlobal
的updateViewLayout
說起晶衷,代碼如下:
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
...
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);
root.setLayoutParams(wparams, false);
}
}
updateViewLayout
方法做的事情就比較簡(jiǎn)單了,首先他需要更新View的LayoutParams
并替換老的LayoutParams
阴孟,接著再更新ViewRootImpl
中的LayoutParams
,這一步是通過ViewRootImpl
的setLayoutParams
方法來實(shí)現(xiàn)的晌纫。在ViewRootImpl
的setLayoutParams
中會(huì)通過scheduleTraversales
方法來對(duì)View
重新測(cè)量布局以及繪制這三個(gè)過程,在performTraversales
會(huì)通過WindowSession
來更新Window
視圖永丝,這個(gè)過程最終是由WMS
的relayoutWindow
來具體實(shí)現(xiàn)的锹漱,同樣也是一個(gè)IPC過程。
參考
- 《Android開發(fā)藝術(shù)探索》
- 《Android源碼設(shè)計(jì)模式》