Android Framework 學習(五):Activity 啓動流程

一、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的層級和位置進行合成,最後顯示出來。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章