activity显示页面流程
对于一个activity启动流程之前已经分析过,那么一个activity页面是怎么绘制出来的呢?如下图:
主要流程总结:
- ActivityThread中启动了activity,会先调用activity的attach方法。
- attach方法中会实例化一个PhoneWindow对象,在PhoneWindow对象中会实例化一个DecorView。
- DecorView会根据Activty的主题配置,选择使用哪个系统的布局文件,然后使用layoutInflate来解析文件为view,提取出其中id为ID_ANDROID_CONTENT的控件,作为activity布局文件的父容器。
- ActivityThread中调用activity方法onCreate,我们在onCreate中会调用setContentView来设置布局。
- setContentView中会使用layoutInflate来解析布局的xml文件为一个view对象,将view对象addView到DecorView的父容器中
- ActivityThread调用了activity的onResume方法,方法执行完成后,activity中会设置DecorView先为不可见,然后将该viewaddView到WMS中。
- addView时候,会先生成一个ViewRootImpl对象,保存DecorView对象,后续所有view刷新操作都由ViewRootImpl来管理。
- viewRootImpl会调用其内部方法requestlayout,来进行view的测量,布局和绘制等流程。
- WMS会和surfaceFlinger进行交互,开始绘制界面显示给用户。
这个流程中,每个activity都会生成一个PhoneWindow对象,该对象实现了Window接口,同时每个PhoneWindow下都会有一个DecorView对象,该对象继承自帧布局。每个DecorView都会被包装到一个ViewRootImpl对象中。APP进程中,只会存在一个Windowmanager代理对象,即WindowManagerGlobal,内部会维护一个WMS代理类。
- 加载布局时候的参数attachRoot为true还是false的区别:
- 如果为true,如下图代码,会将布局对象view插入到root的布局中
- 如果为false,那么生成的view对象,只会使用root中的布局参数,但是不会对root有关联,不会插入到root布局中
if (attachToRoot) {
root.addView(view, params);
} else {
view.setLayoutParams(params);
}
ViewRootImpl的requestlayout方法流程
总结下:
- viewRootImpl的requestlayout方法会调用其内部对象DecorView的方法进行绘制。
- 首先会调用其measure方法进行测量。
- DecorView中会依次调用其子布局的measure方法,分别计算出子布局的大小,最后计算出自己的大小
- 接着会调用DecorView的layout方法,计算其布局位置。
- 同比DecorView会依次遍历其子布局的layout方法,计算出各自的位置
- 最后会调用draw方法,DecorView会调用自己的onDraw方法,接着会通过dispatchView通知子布局调用其onDraw方法进行绘制。
关于MeasureSpec:
- 组成
MeasureSpec是一个int值,但是其内部包含了两个信息,一个是size大小,一个是size的模式,其中高两位是模式mode,低30位是size。
为啥要这样呢?
- 其实就是为了减少内存,每个view都需要两个MeasureSpec,然后一个activity有好多view,每个MeasureSpec都需要记录mode和size,通过这样放到一个int值中,可以减少内存
- 为了使得mode和size可以对应起来
- 关于MeasureSpec中的mode
- 对于布局xml中的设置的width,对应代码中是什么呢?
xml中确切的数值宽度,代码中对应EXACTLY
xml中的MATCH_PARENT,对应EXACTLY
xml中的WRAP_CONTENT,对应AT_MOST
xml中设置为0,对应UNSPECIFIED
- 测绘过程中,如何确认子布局大小的呢?(定义父布局大小为size,子布局为 childSize)
- 如果子布局是 大于0的具体数值, 那么子布局就会以childSize 作为宽高进行计算,模式为EXACTLY
- 如果子布局是 MATCH_PARENT,
父布局是EXACTLY -> 子布局以size为准计算,模式为 EXACTLY
父布局是AT_MOST -> 子布局以size为准计算,模式为 AT_MOST
父布局是 UNSPECIFIED -> 子布局以size为准,模式为 UNSPECIFIED - 如果子布局是 WRAP_CONTENT,
父布局是 EXACTLY -> 子布局以size为准,模式为AT_MOST
父布局是 AT_MOST -> 子布局以size为准,模式为AT_MOST
父布局是 UNSPECIFIED -> 子布局以size为准,模式为 UNSPECIFIED
除此之外,其他情况都是 size为0,模式为UNSPECIFIED
一些问题
- 手机锁屏后,viewRootImplp还会发送屏障消息吗?
不会
手机锁屏,会触发activity的onStop方法,对于viewRootImpl的requestLayout方法,会判断如果activity处于stop状态,那么就不会继续往下走了,而发送屏障消息是在requestLayout中先发送的,所以答案是不会
- requestlayout 和 invalidate的区别
requestLayout是在用于重新绘制整个view树,确定其大小,布局最后进行绘制。而 invalidate 只是用于重新调用当前view的onDraw方法,重新绘制当前view
© 版权声明
文章版权归作者所有,未经允许请勿转载,侵权请联系 admin@trc20.tw 删除。
THE END