0. 概念
- 从上次讲到的启动过程,ActivityThread建立了Activity以后,会将 DecorView添加到Window上去,同时创建ViewRootImpl对象,并且把这个对象和DecorView建立关联,绘制流程就是从ViewRoot的performTraversals开始的,然后measure、layout、draw过程。
- DecorView就是我们看到的Activity的顶层View,他包含的LinearLayout把画面分成上下两部分,上面就是标题栏,下面是contentView,就是Activity->onCreate->setContentView的部分,然后setContentView里面就是onMeasure、onLayout、onDraw过程。
- 优化主要是上面setContentView中的三个过程,并且自定义View和ViewGroup中的这三个过程。
1. 工具
既然是优化,肯定要能看到效果,所以要有数据显示证明优化确实起到了作用
- HierarchyViewer:用法HierarchyViewer
- Systrace: 网上很多
有了上面两个工具就可以直观的看到优化的效果了
2. 优化方法
- LinearLayout效率优于RelativeLayout(同样布局嵌套的情况下),
RelativeLayout会onMeasure两次 - 不带weight的LinearLayout效率优于带weight的LinearLayout,
weight属性会onMeasure两次 - RelativeLayout有利于减少布局的嵌套,LinearLayout只能必须指定子View的方向
- ConstraintLayout 优于任何布局(只是学习了解真正项目中还没用过),学习文章ConstraintLayout
- include 和 merge :布局复用,比如toolbar布局
- ViewStub :懒加载布局,初始化的时候不会初始化ViewStub,比如每个网络请求页面都有的加载失败、网络错误、未登录等页面
- Space:一般用于分割线,onDraw函数是空了,效率高,比如个人中心中的分割线
- 不要在Activity的主题中为Activity设置默认的背景图片,这样会导致Activity占用的内存翻倍
- 用SurfaceView和TextureView 绘制复杂布局和高清大图(也可以使用BitmapRegionDecoder来加载),因为他们都是在非UI线程绘制UI,不会阻塞主线程(项目中还未用到,需要研究).
- Button的点击效果:
尽量不要用两个图片来设置selector,会占用两倍内存
尽量用纯颜色设置点击效果
必须有图片的(业务要求),尽量用.9.png图片
不能用.9.png的用懒加载方式
view.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:{
v.setBackgroundResource(pressResId);
}
break;
case MotionEvent.ACTION_MOVE:{
v.setBackgroundResource(pressResId);
}
break;
case MotionEvent.ACTION_UP:{
v.setBackgroundResource(normalResId);
}
break;
default:{
}
break;
}
return false;
}
});
- ImageView的点击效果也用onTouch事件,用setColorFilter来实现效果,不要用两张图片
- Material Design效果的控件原生都支持点击效果,都不用两张图片
- 尽量合并子控件减少布局嵌套,比如ImageView和TextView可以转换成TextView+drawable等情况
- recyclerview scrollview 尽量不嵌套,可以给recyclerview添加addHeader方法来减少嵌套
3. RecyclerView优化
这个是布局优化的主要部分,因为一个APP中有太多的RecyclerView(以前是ListView),而且卡顿现象一般都在RecyclerView的快速滑动中。
- 首先ViewHolder模式现在是必须用的
- 还是前面说的布局尽量不要嵌套
- 在Item里面尽量不要做耗时的操作,网络请求、IO操作、复杂计算等,异步任务也尽量不要多开
- 快速滑动的时候,可以考虑停止加载耗时任务,降低异步任务的执行频率
- 要用tag绑定来防止item错乱
- 开启硬件加速 有时候能解决卡顿现象
- 背景色什么的尽量不要半透明,会执行大量计算操作
4. Android适配方案
- DP方案,这是Google开始推荐的方案
优点:在相似分辨率下,看起来效果一样,就是绝对大小一样
缺点:在相差很大的分辨率和大小下,效果差别太大,Google建议在且一套图出来
实际项目中使用过,但是效果太差,而且再切一套图不太现实 - 资源目录名方案,这是官方文档在上面基础上推荐的方案
优点:通过运行时找到不同的命名文件来达到适配效果,比上一种方案好很多,只要适配了这个机型就会达到预想的效果
缺点:市场上机型太多,很难适配完全,并且修改起来也很麻烦(虽然有自动生成工具),太耗时
实际项目中使用过,整体效果还好,但是确实有客户反映UI变形了等问题还有修改起来太麻烦 - ConstraintLayout方案:Google推荐
优点:约束布局直接就能适配不同机型
缺点:没有用过,也没研究很深,据说有坑 - AutoLayout方案:网上大牛们基于Google百分比方法开源的方案
优点:操作简单,适配效果不错
缺点:代码中动态修改UI大小会出现问题,并且作者不维护了
目前用的这个方案,出现的问题自己代码里面特殊处理 -
Rudeness: 网上基于AutoLayout改进的方案
没有使用过,正在调研,据说解决了AutoLayout的问题,不知道有没有新问题出现
5. 自定义View
onCreate -> onFinishInflate -> onAttachToWindow -> onMeasure -> onSizeChanged -> onLayout -> onDraw -> onDetachedFromWindow
注意点:
0. onFinishInflate是xml加载完成以后调用
1. onDetachedFromWindow 在这里做释放对象、资源和结束线程的操作
2. invalidate() 和 postInvalidate() 是主动调用onDraw的方法
3. requestLayout() 是主动调用onMeasure 和 onLayout的方法
4. 如果有动画只是调用onDraw没有调用onMeasure 和 onLayout,所以View的实际大小没有改变
5. 测量模式下的三种模式MeasureSpec.UNSPECIFIED、MeasureSpec.EXACTLY、MeasureSpec.AT_MOST
6. 重写onMeasure方法的时候,要特别处理MeasureSpec.AT_MOST和View的padding这两种情况,在测量出宽高以后,一定要设置setMeasuredDimension这个函数.
7. 自定义View主要处理onMeasure,自定义ViewGroup主要处理onLayout,如果是组合View或者ViewGroup主要处理onDraw
8. canvas操作
canvas.translate(100, 50) 平移
canvas.scale(2, 4); 缩放
canvas.rotate(30); 旋转
canvas.save(); 保存状态
canvas.restore(); 恢复状态
canvas.drawText(); 画文字
canvas.drawCircle(); 画圆
canvas.drawLine(); 画线
canvas.drawOval(); 画椭圆
canvas.drawArc(); 画弧度
canvas.drawRoundRect(); 画矩形
canvas.drawPath(); 画多边形
canvas.drawPath(); 画贝塞尔曲线
canvas.drawBitmap(); 画图片
简单有规则的东西直接画,复杂的用Path
网友评论