[TOC]
基础概念
- 屏幕大小
- 对角线长度,如5.5寸手机
- 分辨率
- 手机屏幕的像素点个数
- PPI
- 每英寸像素Pixels Per Inch, 又被称为Dots Per Inch,由对角线的像素点除以屏幕的大小得到
度量单位
- dp、dip
- 设备独立像素
- px、pixels
- 像素,不同设备显示效果相同
- pt、point
- 标准长度单位
- sp:scaled pixels
- 放大像素,主要用于字体显示
- in
- 英寸
- mm
转换
1 | /** |
Android渲染机制
Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染
UI卡顿解决方法:
- 通过Hierarchy Viewer去检测渲染效率,去除不必要的嵌套
- 通过show GPU Overdraw去检测Overdraw
- getWindow().setBackgroundDrawable(null)
- canvas.clipRect
- 移除不必要背景
- 减少没有必要的layouts、invalidations、overdraw
Activity的组成
- Activity
- 基本的页面单元,Activity包含一个Window,window上可以绘制各种view
- Window
- 表示顶层窗口,管理界面的显示和事件的相应;每个Activity均会创建一个
- 当前只有PhoneWindow作为唯一的实现类
- 独占一个Surface实例的显示区域,每个窗口的Surface由WindowManagerService分配。可以把Surface看做一个画布,应用通过Canvas或OpenGL在上面作画
- Activity调用attach,创建了Window
- PhoneWindow
- Activity和整个View系统交互的接口
- phoneWindow是把一个FrameLayout进行了一定的包装,并提供了一组通用的窗口操作接口
- DecorView
- 是PhoneWindow中的一个内部类
- ViewRoot
- 每个DecorView都有一个与之关联的ViewRoot对象,在ActivityThread.handleResumeActivity()方法中建立了它们两者的关联关系。
- 负责绘制
- 调用performTraversals进行绘制
- View
- 最基本的UI组件,表示屏幕上的一个矩形区域
这里面所有View的监听事件,都通过WindowManagerService来进行接收,并通过Activity对象来回调对应的onClickListener
如果调用requestWindowFeature(Window.FEATURE_NO_TITLE),视图树的布局中就仅有Content了,但是requestWindowFeature必须在setContentView之前才能生效
在onCreate()中调用setContentView()后,ActivityManagerService会回调onResume(),此时系统才会把整个DecorView添加到PhoneWindow上,最终完成界面的绘制。(不调用setContentView也会调用onResume)
绘制流程
整个View树的绘图流程是在ViewRoot.java的performTraversals()函数展开的,该函数做的执行过程可简单概括为根据之前设置的状态:
- 判断是否需要重新计算视图大小(measure)
- 判断是否需要安置视图的位置(layout)
- 是否需要重绘(draw)
measure
为整个View树计算实际的大小,即设置实际的高(mMeasuredHeight和mMeasureWidth),每个View控件的实际宽高都是由父视图和本身视图决定的
layout
根据子视图的大小以及布局参数将View树放到合适的位置上
onlayout在View的位置发生改变后调用,内容是对子View重新布局
View#onLayout
所以View的onLayout方法默认为空
ViewGroup#onLayout
调用子View的layout
draw
ViewRoot对象的performTraversals()方法调用draw()方法发起绘制该View树,判断DRAWN位,看是否需要重绘
View#draw
- 绘制背景
- 通过onDraw绘制自身内容
- 通过dispatchDraw()绘制子View
- 绘制滚动条
1 | public void draw(Canvas canvas) { |
requestLayout()
调用measure()和layout()
具体细节推荐此文