上一篇文章圖像顯示深刻學習一:Activity啓動過程中介紹了啓動一個Activity在整個Android系統中執行的流程,其中能夠看到Window的建立,這篇文章就整理一下Window機制的實現過程吧。java
吐個槽,今年大部分時間在公司一直在作SDK項目,UI方面的工做涉及的比較少,如今從新開始作UI了,發現本身對於View方面的知識有點模糊了,後悔之前沒有寫文章記錄下來呀,好記性真的不如爛筆頭。session
從新回顧一下圖像顯示深刻學習一:Activity啓動過程文章中的Activity建立過程,應用層經過ApplicationThread.scheduleLaunchActivity(...)
接受遠程回調,進而調用ActivityThread.handleLaunchActivity(...)
方法,從而開始了一系列Activity生命週期的回調,而Window的建立顯示過程也包含其中,因此咱們仍是從.handleLaunchActivity(...)
該方法開始看起,只摘取出跟Window有關的內容:app
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) { ... WindowManagerGlobal.initialize(); Activity a = performLaunchActivity(r, customIntent); if (a != null) { ... handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason); if (!r.activity.mFinished && r.startsNotResumed) { performPauseActivityIfNeeded(r, reason); ... } }
這裏調用了 WindowManagerGlobal.initialize()
方法, WindowManagerGlobal是與WindowManagerService溝通的橋樑,因此這裏咱們先看下這個方法到底幹了什麼:ide
//WindowManagerGlobal.java public static void initialize() { getWindowManagerService(); } public static IWindowManager getWindowManagerService() { synchronized (WindowManagerGlobal.class) { if (sWindowManagerService == null) { sWindowManagerService = IWindowManager.Stub.asInterface( ServiceManager.getService("window")); try { if (sWindowManagerService != null) { ValueAnimator.setDurationScale( sWindowManagerService.getCurrentAnimatorScale()); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return sWindowManagerService; } }
initialize()
方法中使用Binder通訊機制初始化了sWindowManagerService對象,比較簡單。回到handleLaunchActivity(...)
中,繼續查看performLaunchActivity(...)
:oop
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { //新建Activity activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); r.intent.prepareToEnterProcess(); if (r.state != null) { r.state.setClassLoader(cl); } } catch (Exception e) { if (!mInstrumentation.onException(activity, e)) { throw new RuntimeException( "Unable to instantiate activity " + component + ": " + e.toString(), e); } } try { ... if (activity != null) { ... appContext.setOuterContext(activity); //調用attach初始化Activity相關參數 activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window, r.configCallback); ... //調用onCreate回調 if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); } ... //調用onStart回調 if (!r.activity.mFinished) { activity.performStart(); r.stopped = false; } //調用onRestoreInstanceState回調 if (!r.activity.mFinished) { if (r.isPersistable()) { if (r.state != null || r.persistentState != null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state, r.persistentState); } } else if (r.state != null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); } } //調用onPostCreate回調 if (!r.activity.mFinished) { activity.mCalled = false; if (r.isPersistable()) { mInstrumentation.callActivityOnPostCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnPostCreate(activity, r.state); } if (!activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onPostCreate()"); } } } ... return activity; }
該方法設計到的Window操做很少,就一個activity.attach(...)
,爲了方便,下面把源碼貼出來一下:佈局
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, ActivityConfigCallback activityConfigCallback) { ... mWindow = new PhoneWindow(this, window, activityConfigCallback); mWindow.setWindowControllerCallback(this); mWindow.setCallback(this); mWindow.setOnWindowDismissedCallback(this); mWindow.getLayoutInflater().setPrivateFactory(this); ... 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; mWindow.setColorMode(info.colorMode); }
attach(...)
方法中主要作了兩件事情:post
mWindow.setWindowManager(....)
會去實例化一個WindowManager實現類WindowManagerImpl:學習
//Window.java public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) { ... mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this); } //WindowManagerImpl.java public WindowManagerImpl createLocalWindowManager(Window parentWindow) { return new WindowManagerImpl(mContext, parentWindow); }
PhoneWindow是Window的繼承類,每個Window行爲都由PhoneWindow執行。好的,接着繼續往下看handleResumeActivity(...)
方法:this
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) { ... //回調onResume方法 ... if (!willBeVisible) { try { willBeVisible = ActivityManager.getService().willActivityBeVisible( a.getActivityToken()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } if (r.window == null && !a.mFinished && willBeVisible) { //1. r.window = r.activity.getWindow(); //2. View decor = r.window.getDecorView(); //首先設置DecorView不可見狀態 decor.setVisibility(View.INVISIBLE); ViewManager wm = a.getWindowManager(); //Window在初始化的時候也會初始化一個LayoutParams,該LayoutParams是一個 //WindowManager.LayoutParams對象 WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; ... if (a.mVisibleFromClient) { if (!a.mWindowAdded) { a.mWindowAdded = true; //3 wm.addView(decor, l); } ... } } ... //4 if (r.activity.mVisibleFromClient) { ViewManager wm = a.getWindowManager(); View decor = r.window.getDecorView(); wm.updateViewLayout(decor, l); } } r.activity.mVisibleFromServer = true; mNumVisibleActivities++; //5. if (r.activity.mVisibleFromClient) { r.activity.makeVisible(); } } ... }
上面桉序列依次解釋代碼的邏輯:spa
其中須要解釋的是DecorView實例,關於Activity中佈局的示意圖以下:
能夠看到DecorView位於佈局的最上游,本質上是一個FrameLayout,那麼,DecorView是何時添加進去的呢?答案就是在setContentView(...)
調用的時候,經過在圖像顯示深刻學習二:setContentView(...)過程分析一文中瞭解到了DecoView會在setContentView(...)
時候初始化,也就是在onCreate(...)
方法回調以後。
接下來就要着重講下WindowManager了,WindowManager自己是一個接口類,繼承了ViewManager接口,關於ViewManager的定義以下:
public interface ViewManager { //向窗口添加VIew public void addView(View view, ViewGroup.LayoutParams params); //更新窗口中的View public void updateViewLayout(View view, ViewGroup.LayoutParams params); //移除View public void removeView(View view); }
在WindowManager內部中有一個內部靜態類LayoutParam,該類實現了Parcelable接口,也就是說提供了序列化的能力,這裏先猜想跟Binder通訊有關,下面再進行考證。
WindowManager的實現類爲WindowManagerImpl,WindowManagerImpl內部持有了一個WindowManagerGlobal實例,在上面分析中咱們知道WindowManagerGlobal持有了遠程WindowManagerService的Binder對象,那麼進行Binder通訊確定就經過WindowManagerGlobal進行了,下面看下WindowManagerImpl的主要實現:
public final class WindowManagerImpl implements WindowManager { ... @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); } ...
這裏的mGlobal就是WindowManagerGlobal對象,能夠看到其實WindowManagerImpl也就只是一個代理類,調用ViewManager的方法,實際是調用到了WindowManagerGlobal(WMG)中。接下來就要着重挑一個addView(...)
的研究,在研究以前,先整理一下上面的邏輯:
ApplicationThread.scheduleLaunchActivity(...)
被AMS遠程回調後,在會去初始化WindowManagerGlobal與WMS進行溝通的Binder對象。Activity.attach(...)
時候會在內部建立一個PhoneWindow做爲Window的實現類。而後回調Activity的onCreate(...)
,onStart(...)
等方法,在onCreate(...)
時候會經過setContentView(...)
建立DecorView。onResume(...)
方法,而後調用WindowManager的addView(...)
以及updateViewLayout(...)
方法。在WMG中有三個變量須要注意一下:
//記錄全部Windowsd對應的View private final ArrayList<View> mViews = new ArrayList<View>(); //記錄mViews中對應的ViewRootImpl private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>(); //記錄全部Window對應的Param private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>(); //記錄正在被刪除的Views private final ArraySet<View> mDyingViews = new ArraySet<View>();
好的接下來看下WMG的addView(...)
方法:
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { //判空 ... final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; ... ViewRootImpl root; View panelParentView = null; ... //新建ViewRootImpl類 root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); //1 mViews.add(view); mRoots.add(root); mParams.add(wparams); // do this last because it fires off messages to start doing things try { //2 root.setView(view, wparams, panelParentView); } catch (RuntimeException e) { // BadTokenException or InvalidDisplayException, clean up. if (index >= 0) { removeViewLocked(index, true); } throw e; } } }
上面代碼首先在三個變量作添加對應DecorView變量的信息,而後調用第2步代碼(root是一個ViewRootImpl對象,該類掌管着View的測量,佈局以及繪圖的主要邏輯):
... mWindowSession = WindowManagerGlobal.getWindowSession(); ... public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { if (mView == null) { mView = view; ...//1 requestLayout(); ... //2 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, 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); } finally { ... }
上面省略了大部分的代碼,步驟1首先看調用了requestLayout()
方法,咱們在平常中使用的requestLayout()
方法其實到最後就是調用ViewRootImpl的requestLayout()
方法:
@Override public void requestLayout() { if (!mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = true; scheduleTraversals(); } } void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); if (!mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); pokeDrawLockIfNeeded(); } }
這裏涉及到Choreographer(編舞者)類,簡單來就是使用Handler進行post(...)
操做,因爲Handler以及消息隊列機制的緣由,該post(...)
須要在咱們執行完ActivityThread.handleLaunchActivity(....)
才能執行,也就是說窗口添加完畢了,post(...)
纔會調用,因此等咱們下面分析完再回過頭了分析這個。
步驟2主要工做就是在於跟WMS進行通訊,經過調用mWindowSession.addToDisplay(...)
方法,mWindowSession是一個IWindowSession,通常出現I字開頭的在系統層代碼中都表明着有Binder支持的進程通信能力,咱們看下該類怎麼得到到的:
//WindowManagerGlobal.java public static IWindowSession getWindowSession() { synchronized (WindowManagerGlobal.class) { if (sWindowSession == null) { try { InputMethodManager imm = InputMethodManager.getInstance(); IWindowManager windowManager = getWindowManagerService(); sWindowSession = windowManager.openSession( new IWindowSessionCallback.Stub() { @Override public void onAnimatorScaleChanged(float scale) { ValueAnimator.setDurationScale(scale); } }, imm.getClient(), imm.getInputContext()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return sWindowSession; } }
經過WMS對象打開一個Session,每一個Session是一個Window的Native的代理類,WMS經過掌管不一樣的Session與應用層的Window進行通訊:
//WindowManagerService.java @Override public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client, IInputContext inputContext) { if (client == null) throw new IllegalArgumentException("null client"); if (inputContext == null) throw new IllegalArgumentException("null inputContext"); Session session = new Session(this, callback, client, inputContext); return session; }
接下來繼續看mWindowSession.addToDisplay(...)
方法在Native層的調用的:
//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); }
Seesion中從新調回WMS在addWindow(...)
方法:
public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { int[] appOp = new int[1]; //檢察權限 int res = mPolicy.checkAddPermission(attrs, appOp); if (res != WindowManagerGlobal.ADD_OKAY) { return res; } ... final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId); ... //判斷Window合法性 ... ... res = WindowManagerGlobal.ADD_OKAY; ... return res; }
改代碼中建立一個DisplayContent以及WindowState(真正表示一個Native Window與應用層對應),這些主要跟Surface有關,這裏就先不分析了,到時候寫一篇關於Surface的文章再作記錄。最終返回WindowManagerGlobal.ADD_OKAY。
ok到此Window在Native的添加已經完畢,那咱們接着返回查看ViewRootImpl.setView(...)
方法中的requestLayout(...)
方法。上面講到該方法最終調用到mTraversalRunnable實例中,那麼看下該Runnable對象幹了什麼東東:
final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); } }
這裏調用doTraversal()
方法,該方法最終又調用performTraversals()
方法,該方法就是最終管理View的測量,佈局,繪圖的最頂層方法:
private void performTraversals() { // cache mView since it is used so much below... final View host = mView; ... //賦值系統Window的寬高 int desiredWindowWidth; int desiredWindowHeight; ... relayoutResult = relayoutWindow(params, viewVisibility, insetsPending); ... //測量 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); ... //佈局 performLayout(lp, mWidth, mHeight); ... //繪圖 performDraw(); ... }
首先這裏有relayoutWindow(params, viewVisibility, insetsPending)
操做,該方法內部會建立一個Surface對象與ViewRootImpl關聯起來,這裏作個筆記,下次對Surface分析的時候有用。下面方法主要就是測量,佈局,繪圖過程了,這裏不對測量,佈局,繪圖過程進行細究了,他們最終依次回調onMeasure(...)
,onLayout(...)
,onDraw(...)
方法。