Android framework:Activity的显示原理

慕课网 剖析framework 笔记

 

4-2 Activity的显示原理

看看相关问题,了解UI涉及的内容;对比他们考察的点,不要弄混:

1,Activity的显示原理:

它是关于Window/DecorView/ViewRoot的概念的

2,Activity的UI刷新机制

是关于Vsync/Choreographer的

3,UI的绘制原理

关于Measure/Layout/Draw的

4,Surface原理

surface/SurfaceFlinger

 

看看这次的题目:Activity的显示原理:

1,setContentView的原理:

我们在onCreate经常调它,应该非常熟了,但是它的原理是?里面做了什么?

2,Activity在onResume后才能显示的原因?里面做了什么重要的事情?

3,ViewRoot是什么?它是ViewTree的Root View吗?

 

先看看setContentView

平时新建Activity,都是先给Activity写好布局,然后setContentView加载布局,然后等待显示出来就行了,

看看它的原理:

public void setContentView(int layoutResID){
    //拿到window对象,调用它的对象
    getWindow().setContentView(layoutResID);
    ...
}

//它返回window对象,private Window mWindow;
public Window getWindow(){
    return mWindow;
}

 

 

看看Activity的mWindow对象在哪里初始化的,

是在Activity的attach函数里面init的,

final void attach(Context context,){
    .....
    //new了一个PhoneWIndow,它是干嘛的?它是手机的window,用来管理手机的窗口,不只是AP内容区域,还管理其他区域
    mWindow = new PhoneWIndow(this);
}

 

讲Activity启动的时候说过,step:

创建Acitivity对象

创建Context对象

准备Application对象

attach上下文,这里不只是context,还有其他重要的变量要init,如window

调用Activity onCreate回调。

 

所以onCreate的时候,可以拿到mWindow

 

再看看window的setContextView,

public void setContentView(int layoutResID){
    //mContentParent是content view的parent,就是一个view contener,装content view的
    if(mContentParent == null){
        installDecor();
    }
    //加载布局用,参数1是要加载的布局的ID,这会生成一个ViewTree,
    //参数2是ViewTree的Parent,
    //就是给生成的View加入Parent里面
    mLayoutInflater.inflate(layoutResID, mContentParent);
}

//看看installDecor做什么用的
//就是创建好一个DecorView,init整个屏幕的页面布局,把自己的布局加入Content里面,
//这里只是加载了布局,建立了ViewTree,顶多算是一个数据结构,页面还不能显示,
//想把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);
}

 

看看handleResumeActivity

页面显示是在onResume()回调之后,

而前面讲的setContentView是在onCreate里面加载的布局,生成了ViewTree

那么OnResume()又做了什么才能让界面显示?关键就是这一步handleResumeActivity函数

之前讲Activity启动时就讲过了,之前把重点放在生命周期回调,现在重点放在UI上

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(mWindow,...);

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, ...){
    //在WMS创建Window相关对象,WMS统一管理所有Window的位置,层次,大小
    //这样有什么用?
    //对于WMS来说,它不关注AP本地的WIndow对象,也不关注AP端的View,
    //它的重要功能就是给AP端的Window分配Surface,并且掌管这些Surface的显示顺序,位置,和尺寸,
    //当AP端在Surface绘制完,SF把Surface的图像数据按照WMS里面提供的Surface的层级和位置进行合成,最后显示出来。
    return mSerview.addWindow(this, window, seq, attrs,...);
}

 

//在WMS创建Window相关对象,WMS统一管理所有Window的位置,层次,大小

//这样有什么用?

//对于WMS来说,它不关注AP本地的WIndow对象,也不关注AP端的View,

//它的重要功能就是给AP端的Window分配Surface,并且掌管这些Surface的显示顺序,位置,和尺寸,

//当AP端在Surface绘制完,SF把Surface的图像数据按照WMS里面提供的Surface的层级和位置进行合成,最后显示出来。

 

WMS的主要作用:

1,分配Surface

2,掌管Surface显示顺序和位置尺寸等

3,控制窗口动画

4,输入事件分发

 

总结:

ACtivity启动的时候会创建PhoneWindow,

PhoneWindow里面有一个DecorView,它是整个Activity的ViewRree的RootView,

ContentView只是DecorView的一部分

 

DecorView会对应一个ViewRootImpl对象,它是可以与WMS双向通信的,

ViewRootImpl可以通过IWindowSession向WMS发起binder调用

WMS通过IWindow向ViewRootImpl发起binder调用,

 

Activity能显示出来的最重要的一步:

为DecorView创建ViewRootImpl对象,并且用ViewRootImpl对象全权负责DecorView的绘制,

ViewRootImpl在WMS里面注册窗口,WMS统一管理窗口的大小,位置,层次,

第一次绘制时,ViewRootImpl还会向WMS申请一个Surface,有了Surface,AP就可以进场绘制。

绘制后,SurfaceFlinger里面就可以按照WMS提供的层级,位置,对Surface进场合成

然后写到FrameBuffer显示出来

 

 

 

 

总结:说说Activity的显示原理

最好的方式是照着图给整个流程屡屡

1,PhoneWIndow是什么,怎么创建的

2,setContentView原理,DecorView是什么?

4,ViewRoot是什么,有什么作用

5,View的显示原理是什么,这个过程WMS发挥了什么作用

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值