zoukankan      html  css  js  c++  java
  • 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的层级和位置进行合成,最后显示出来。

  • 相关阅读:
    C# 空合并运算符 ??
    基于ASP.NET Core 创建 Web API
    使用 csc.exe 编译C#代码
    NPOI创建Excel批注
    http协议 put、delete请求asp.net mvc应用,报404错误
    visual studio清理nuget包缓存
    String.IsNullOrEmpty 与 String.IsNullOrWhiteSpace
    C# linq to xml 简单示例
    SQL Server修改表结构,不允许保存更改。
    SQL Server 分离与附加数据库
  • 原文地址:https://www.cnblogs.com/renhui/p/12951249.html
Copyright © 2011-2022 走看看