丢帧的各种原因:
- layout 太过复杂,层次过多,UI 上有层叠太多的绘制单元,过度绘制
- CPU 或者 GPU 负载过重
- 动画执行的次数过多(简单的说就是一大堆动画重复了一遍又一遍,消耗 CPU 、 GPU 资源)
- 频繁 GC,主要是内存抖动
- UI 线程执行耗时操作(所以要放在子线程执行好使操作)
分析与建议解决
Layout 太过复杂,层次过多,UI 上有层叠太多的绘制单元,过度绘制
对于我们layout文件,层级越多,android在初始化他们时,也就是渲染时就越浪费时间。所以布局的优化其实说白了就是减少层级,越简单越好,减少overdraw( 过度绘制是一个术语,表示某些组件在屏幕上的一个像素点的绘制次数超过 1 次。),就能更好的突出性能。
常用布局大解析:
LinearLayout和RelativeLayout 性能大比拼:LinearLayout 在 measure 的时候,在横向或者纵向会去测量子 View 的宽度或高度,且只会测量一次。但是当设置 layout_weight 属性的时候会去测量两次才能获得精确的展示尺寸。 RelativeLayout 在 measure 的时候会在横向和纵向各测量一次。也就是需要两次度量来确保自己处理了所有的布局关系。高能:如果带有 weight 属性的 LinearLayout 或者 RelativeLayout 被套嵌使用,measure 所费时间可能会呈指数级增长(两个套嵌的叶子 view 会有四次 measure,三个套嵌的叶子 view 会有8次的 measure)。为了缩短这个时间,保持树形结构尽量扁平(深度低),而且尽量要移除所有不需要渲染的 view。
那么我们给怎样使用这两个布局呢:告诉你,视情况而定。
- 尽量避免在视图层级的顶层使用相对布局 RelativeLayout 。相对布局 RelativeLayout 比较耗资源,因为一个相对布局 RelativeLayout需要两次度量来确保自己处理了所有的布局关系。
- 布局层级一样的情况建议使用线性布局 LinearLayout 代替相对布局 RelativeLayout,因为线性布局 LinearLayout 性能要更高一些;
- 当LinearLayout 需要嵌套才能实现的复杂布局,建议使用RelativeLayout
- 尽量避免使用 layoutweight 属性。(但是的确在等分布局时挺好用的,你说是不是,哎,我承认我在用)
其他布局优化
- include标签 (引入布局)
- merge标签(简单粗暴点回答:干掉一个view层级。主要作用是为了防止在引用布局文件时产生多余的布局嵌套)
- ViewStub标签(一句话总结:高效占位符。ViewStub是View的一种,但是它没有大小,没有绘制功能,也不参与布局,资源消耗非常低。主要作用是把我们不常用的view在我们需要的时候才去加载)
注意:如果你这上面三个布局不知道,别告诉我你是android的,让ios笑话。哎,我这么善良。
Android最新的布局方式ConstaintLayout(其实人家ios早就使用了,也就是拖拽布局)
ConstraintLayout允许你在不适用任何嵌套的情况下创建大型而又复杂的布局。它与RelativeLayout非常相似,所有的view都依赖于兄弟控件和父控件的相对关系。但是,ConstraintLayout比RelativeLayout更加灵活,目前在AndroidStudio中使用也十分方便。
过度绘制:过渡绘制是一个术语,表示某些组件在屏幕上的一个像素点的绘制次数超过 1 次。过度绘制导致的问题是花了太多的时间去绘制那些堆叠在下面的、用户看不到的东西,浪费了 CPU 周期和渲染时间。
优化:
- 去除重复或者不必要的 background
- 点击态中的 normal 尽量设置成 transparent
- 去除 window 中的 background(这个可以通过处理 decorView 或者设置 Theme 的方式)
CPU 或者 GPU 负载过重
UI 线程是应用的主线程,很多的性能和卡顿问题是由于在主线程中做了大量的工作。除了主线程外,子线程占用过多 CPU 资源也会导致渲染性能问题。 在 UI 渲染的过程中,是 CPU 和 GPU 共同合作完成的,其中 CPU 负责把 UI 组件计算成 Polygons,Texture 纹理,然后交给 GPU 进行栅格化渲染。如果您在主线程做了耗时的操作,简单的会造成界面的卡顿,严重的直接anr了。
各界面耗时操作anr时间对比:
- 主线程:5秒
- 广播接收者:10秒
- 服务:20s
频繁GC
如果您频繁创建大对象或者频繁创建大量对象,并且这些对象属于用完就废弃的。那么恭喜您,这可能会导致内存抖动的问题。
其实也没啥好用的办法
一个大神说的:其实也挺好理解 大对象可以使用对象池复用,比如 byte[] 尽量在 16ms 内少创建对象,比如在 onDraw 中创建 Paint 对象,decode Bitmap 之类的
其他优化
如果是一些简单的图片,写shape吧,别让美工切图了!
如果是可拉伸的图片背景,用draw9patch吧,如果您不会,请你移步
登录 | 立即注册