基礎
構造函數
ActivityThread#handleResumeActivity()->WindowManagerImpl#addView()->WindowManagerGlobal#addView()->ViewRootImpl(view.getContext(),Display)。
構造函數中會將第一個參數賦值給ViewRootImpl的全局變量mContext。handleResumeActivity傳入的View對象是Window#mDecor,所以view.getContext()返回的就是DecorView所指的Activity實例。
擇一部分構造函數中的代碼如下:
mWindowSession = WindowManagerGlobal.getWindowSession();
mWindow = new W(this);
mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
第一句mWindowSession賦值爲WindowManagerGlobal.getWindowSession(),其返回值爲一個Session對象,Session的實例化在WMS進程中進行的,本應該中有一個Session的代理對象,所以可以通過Session主要調用WMS中一些方法。
第二、三句中的W繼承於IWindow.Stub,後者繼承於Binder又實現了IWindow接口,因此這個W是可以IPC的。第三句中將mWindow賦值給了View.AttachInfo中的mWindow對象,將mWindowSession賦值給了mSession變量。
setView
與構造函數調用時機相同,並且View參數也相同。所以ViewRootImpl中的mView指的是該ViewRootImpl指依賴的Activity中的DecorView。因此它可以通過調用mView來繪製一個Acitivity組件的UI。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
//略
requestLayout();
//略
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
}
//略
}
}
}
而requestLayout->scheduleTraversals()->Choreographer#postCallback()->……->postCallbackDelayedInternal()->scheduleFrameLocked()->scheduleFrameLocked(),它發一個what爲MSG_DO_FRAME的msg->doFrame()。
在這個過程中,有必要跟蹤一下scheduleTraversals()的參數,在postCallbackDelayedInternal()之前,都是正常傳遞的。postCallbackDelayedInternal()如下:
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {//前兩個參數就是scheduleTraversals()中的參數,token爲Null,delayMills爲0
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
//上一步將三個參數封裝成CallbackRecord對象,並通過隊列存儲
if (dueTime <= now) {//由於delayMills爲0,所以走這一步
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
到doFrame()時,有這麼一句話:
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
其中第一個參數就是scheduleTraversals()的第一個參數,而doCallBacks()中又會調用CallbackRecord#run()。 public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
((Runnable)action).run();
}
}
因此到這裏之後,會執行scheduleTraversals()中的第二個參數。其第二個參數->doTraversal()->performTraversals(),在這個方法中會執行View的measure,layout與draw。到這裏,requestLayout()方法執行完畢,其作用就是將View樹測量、佈局與繪製。
而在setView()中,還調用了mWindowSession#addToDisplay(),由於mWindowSession是WMS創建的Session對象在本應用中的一個代理,所以mWindowSession#addToDisplay()便會執行到WMS所在的進程中。而Session中該方法很簡單,只是添加一個參數(this指代的是Session對象自身)然後傳到WMS#addWindow()中。