一、Activity啓動步驟
Activity的啓動流程爲:創建Activity對象 ==> 準備好Application ==> 創建ContextImpl ==> attach應用上下文 ==> 生命週期onCreate回調。
Activity的mWinodw對象就是在attach方法執行的時候創建的。所以我們能夠在onCreate的方法中使用mWindow。
final void attach(Context context,){ //new了一個PhoneWIndow,用來管理手機的窗口,不只是AP內容區域,還管理其他區域 mWindow = new PhoneWIndow(this); //... }
二、setContentView 的原理
下面我們看一下Activity的setContentView的方法執行的代碼,如下:
public void setContentView(int layoutResID){ //mContentParent是content view的parent,即ViewGroup if(mContentParent == null){ installDecor(); } //加載佈局用,參數1是要加載的佈局的ID,這會生成一個ViewTree,參數2是ViewTree的Parent,生成的View會加入Parent裏面 mLayoutInflater.inflate(layoutResID, mContentParent); }
//在installDecor方法中創建好一個DecorView,init整個屏幕的頁面佈局,把自己的佈局加入Content裏面, //這裏只是加載了佈局,建立了ViewTree的數據結構,此時頁面還不能顯示,還需後續的很多步驟 private void installDecor(){ //DecorView其實是一個FrameLayout,是手機整個頁面的rootView mDecor = new DecorView(getContext()); //layoutResource是根據window的feature選的一個系統佈局,加載好後會添加到DecorView裏面 View in = mLayoutInflater.inflate(layoutResource, null); mDecor.addView(in,...); //找到了我們的content parent, mContentParent = findViewById(ID_ANDROID_CONTENT); }
三、在onResume回調後爲何能展示出來佈局
關鍵的函數爲handleResumeActivity,其核心代碼如下:
final void handleResumeActivity(IBinder token,){ //觸發activity的onResume回調,然後再處理UI顯示問題 ActivityClientRecord r = performResumeActivity(token,); final Activity a = r.activity; if(r.window == null && !a.mFinished){ r.window = r.activity.getWindow(); //拿到了DecorView View decor = r.window.getDecorView(); ViewManager wm = a.getWindowManager(); a.mDecor = decor; //把DecorView加到WindowManager裏面,後面看看這個函數 wm.addView(decor, l); } //讓它變得可見,這裏不重要,只是觸發了一次重繪, //mDecor.setVisibility(View.VISIBLE); //真正重要的是誰啓動和管理整個View繪製的流程 r.activity.makeVisible(); } void addView(View view, ViewGroup.LayoutParams params,){ //創建一個ViewRootImpl對象 ViewRoot root = new ViewRootImpl(view.getContext(),); //DecorView交給ViewRootImpl對象管理 root.setView(view. wparams, panelParentView); } public void setView(VIew view,){ //一個ViewRootImpl只能一個管理ViewTree,所以做判斷,mView是null纔行 if(mView == null){ mView = view; //1,requestLayout觸發第一次繪製 requestLayout(); ... //2,addToDisplay是binder調用 mWindowSession.addToDisplay(mWindow,..); ... } } //分別看看上面的1,2 public void requestLayout(){ .... scheduleTraversals(); } void scheduleTraversals(){ ...... //往Choreographer post一個名爲mTraversalRunnable的callback //這個callback會在下一次vsync到來時被觸發。 mChoreographer.postCallback(...,mTraversalRunnable, null); } //看看這個callback裏面幹嘛的 class TraversalRunnable implements Runnable{ public void run(){ //看看它 doTraversal(); } } void doTraversal(){ //這是真正執行繪製的地方 performTraversal(); } //看看它的實現,有4個重要步驟 private void performTraversals(){ .... //1,向WMS申請surface, relayoutWindow(params,...); .... //這3個大家很熟悉了,不講了 performMeasure(childWidthMeasureSpec,...); .... performLayout(lp, desiredWindowWidth,...); .... performDraw(); .... } //1,申請Sureface int relayoutWindow(WindowManager.LayoutParams params, ...){ //拿到一個WindowSession,調用它的relayout函數, //它的一個參數是mSurface,這時它還是一個空殼,當函數返回後,mSurface就可以用了 //有了Surface,接下來的繪製就有了Buffer了,繪製好後,送給SurfaceFlinger, //SF合成好圖形,就可以送給FrameBuffer,並顯示出來 mWindowSession.relayout(..., mSurface); }
這裏重點提一下mWindowSession.addToDisplay方法:
public void setView(VIew view,){ //一個ViewRootImpl只能一個管理ViewTree,所以做判斷,mView是null纔行 if(mView == null){ mView = view; //1,requestLayout觸發第一次繪製 requestLayout(); ... //2,addToDisplay是binder調用 mWindowSession.addToDisplay(mWindow,..); ... } } mWindowSession.addToDisplay(mWindow,..); //WindowSession是幹嘛的? //它是通過WMS的openSession函數返回的binder對象 IWindowManager windowManager = getWindowManagerService(); SWindowSession = windowManager.openSession(...); //openSession: IWindowSeesion openSession(IWindowSessionCallback callback,...){ //new了一個Session對象, //session是用來給應用與WMS通信的,應用拿到session對象就可以向WMS發起binder調用 Session session = new Session(this, callback, client, inputContext); return session; } //現在看看addToDisplay是幹嘛的 mWindowSession.addToDisplay(mWindow,..); //參數mWindow對象是一個binder對象, //這個binder對象註冊到WMS後,AP和WMS就可以雙向調用, static class W extends IWindow.Stub{...} //addToDisplay調到WMS端的addWindow public int addToDisplay(IWindow window, int seq, ...){ return mSerview.addWindow(this, window, seq, attrs,...); }
在WMS中會創建Window相關對象,WMS統一管理所有Window的位置,層次,大小,對於WMS來說,它不關注本地的Window對象,也不關注View,它的重要功能就是給Window分配Surface,並且掌管這些Surface的顯示順序,位置,和尺寸,把Surface的圖像數據按照WMS裏面提供的Surface的層級和位置進行合成,最後顯示出來。