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的层级和位置进行合成,最后显示出来。

 

posted @ 2020-05-25 21:56  灰色飘零  阅读(643)  评论(0编辑  收藏  举报