卡顿分享
- 什么是卡顿
- 如何衡量卡顿
- 产生卡顿的原因
- 卡顿优化
- 工具使用
什么是卡顿
卡顿是人的一种视觉感受,比如我们滑动界面时,如果滑动不流畅我们就会有卡顿的感觉,这种感觉我们需要有一个量化指标,在编程时如果开发的程序超过了这个指标我们认为其是卡顿的。
FPS(帧率):每秒显示帧数(Frames per Second)。表示图形处理器每秒钟能够更新的次数。高的帧率可以得到更流畅、更逼真的动画。一般来说12fps大概类似手动快速翻动书籍的帧率,这明显是可以感知到不够顺滑的。30fps就是可以接受的,但是无法顺畅表现绚丽的画面内容。提升至60fps则可以明显提升交互感和逼真感。
开发app的性能目标就是保持60fps,这意味着每一帧你只有16ms≈1000/60的时间来处理所有的任务。Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps。
如果你的某个操作花费时间是24ms,系统在得到VSYNC信号的时候就无法进行正常渲染,这样就发生了丢帧现象。那么用户在32ms内看到的会是同一帧画面。
如果此时用户在看动画的执行或者滚动屏幕(如RecyclerView),就会感觉到界面不流畅了。
流畅的情况下:
出现了丢帧现象(卡顿)
严重丢帧(卡死了)
如何衡量卡顿
FPS的高低不能准确的反映应用的流畅度。如下图所示,只有有更新的时候才刷新界面。
当界面没有变动的时候,手机不需要对界面进行更新,所以此时的FPS会很低,如果1秒钟内都没有变动那么FPS=0。所以我们需要利用其他方式来衡量应用的流畅度,比如可以利用丢帧数来衡量。
单位时间内丢帧数可以反映出应用是否流畅。不丢帧是终极目标,但每秒丢帧在6-7帧左右可以接受,如果丢10帧以上就需要优化了。
丢帧情况(单位时间内均匀分布) | 卡顿情况 |
0-10帧 | 流畅 |
10-20帧 | 较卡 |
20-40帧 | 很卡 |
40-60帧 | 卡死了 |
对于我们开发人员来说,会使用一些工具找出卡顿比较集中的地方,找出原因,消除或减弱卡顿
卡顿的原因
核心:分析在16ms中我们的应用做了什么工作,哪些工作阻止我们在16ms时更新界面。
分为两大类:
界面绘制,主要原因是绘制的层级深、页面复杂、刷新不合理,由于这些原因导致卡顿的场景更多出现在 UI 和启动后的初始界面以及跳转到页面的绘制上。
数据处理,导致这种卡顿场景的原因是数据处理量太大,一般分为三种情况:
1、数据在处理 UI 线程,
2、数据处理占用 CPU 高,导致主线程拿不到时间片,
3、内存增加导致 GC 频繁,从而引起卡顿。
卡顿优化
分为:布局优化,避免过度绘制,优化逻辑,针对ListView的性能优化。
布局优化
在Android UI布局过程中,通过遵守一些惯用、有效的布局原则,我们可以制作出高效且复用性高的UI,概括来说包括如下几点:
1、尽量多使用RelativeLayout和LinearLayout,不要使用绝对布局AbsoluteLayout:
a、在布局层次一样的情况下,建议使用LinearLayout代替RelativeLayout。(因为RelativeLayout会让子View调用2次onMeasure, LinearLayout 在有weight属性时,才会让子View调用2次onMeasure。onMeasure的耗时越长那么绘制效率就低)
b、若使用线性布局LinearLayout排版导致UI层级深度。我们可以使用相对布局RelativeLayout代替多个LinearLayout,减少UI的层次。
c、 尽量避免RelativeLayout嵌套RelativeLayout。
d、 复杂层级的布局可使用ConstraintLayout来减少级,ConstraintLayout是一个非常强大的布局控件,很多相对复杂的布局都可以使ConstraintLayout一个层级就可以实现功能。(例子:item_space_vpian.xml)https://segmentfault.com/a/1190000014876944
- 将可复用的组件抽取出来并通过include标签使用。
- 使用ViewStub标签来加载一些不常用的布局。
不常用的UI经常被设置成了GONE,比如error页面,断网页面,如果有这类问题,我们可以用<ViewStub/>标签代替GONE提高UI性能。<ViewStub/>标签是当你需要时才会加载,使用它并不会影响UI初始化时的性能。以减少内存使用量,加快渲染速度。
4、使用merge标签减少布局的嵌套层次。https://www.jianshu.com/p/69e1a3743960
- 包含ImageView和TextView的LinearLayout可以使用包含图片的Textview,这样更高效。
- 内嵌使用包含layout_weight属性的LinearLayout会在绘制时消耗系统资源,因为每一个子组件都需要被测量两次。在使用ListView与GridView的时候这个问题显得尤其重要,因为子组件会重复被创建,所以要尽量避免使用Layout_weight。
- 尽可能少用wrap_content。wrap_content 会增加布局 measure 时计算成本,在已知宽高为固定值时,不用wrap_content 。
- 删除控件中无用的属性。
9、无用的命名空间。
避免过度绘制
Overdraw(过度绘制)描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次(至少两次)。在多层次的UI结构里面,如果不可见的UI也在做绘制的操作,这就会导致某些像素区域被绘制了多次,这就浪费大量的CPU以及GPU资源。
我们可以通过手机设置里面的开发者选项,打开“调试GPU过度绘制”选项,可以观察UI上的过度绘制情况。
我们的目标就是尽量减少红色区域,看到更多的蓝色区域。
如何避免过度绘制,如下:
- 移除 XML 中非必须的背景,有多层背景颜色的Layout来说,留最上面一层的颜色即可,其他底层的颜色都可以去掉。
- 移除 Window 默认的背景、按需显示背景图片。
- 自定义View优化。使用 canvas.clipRect()来帮助系统识别那些可见的区域,只有在这个区域内才会被绘制。(如侧拉菜单,当菜单显示的时候被菜单遮挡的部分是不用进行绘制的,一旦绘制就会出现过渡绘制现象。)
4、对于使用Selector当背景的Layout(比如ListView的Item,会使用Selector来标记点击,选择等不同的状态),可以将normal状态的color设置为“@android:color/transparent”,来解决对应的过度绘制。
注意:vv音乐里PullToRefreshForListView不需要背景时样式使用vvPullToRefreshEx
优化逻辑
找出在主线程里耗时较大的函数,看看是否能够通过优化逻辑去减少API的耗时。总结以下:
1、不要阻塞UI线程,占用CUP较多的工作尽可能放在子线程中执行。如IO操作(文件IO、网络IO、数据库操作等)。
2、避免UI线程与其他线程持有的锁竞争;
3、避免频繁GC(频繁new一个对象)
4、需要结合使用场景选择不同的线程处理方案
AsyncTask:为UI线程与工作线程之间进行快速的切换提供一种简单便捷的机制。适用于当下立即需要启动,但是异步执行的生命周期短暂的使用场景。
HandlerThread: 为某些回调方法或者等待某些任务的执行设置一个专属的线程,并提供线程任务的调度机制。
ThreadPool: 把任务分解成不同的单元,分发到各个不同的线程上,进行同时并发处理。
IntentService: 适合于执行由UI触发的后台Service任务,并可以把后台任务执行的情况通过一定的机制反馈给UI。
如果大量操作数据库数据时建议使用批处理操作。如:批量添加数据。 启动优化,通过对启动速度的监控,发现影响启动速度的问题所在,优化启动逻辑,提高应用的启动速度。可以采用异步加载、延期加载策略来提高应用启动速度。
例:DiscoverPlayerActivity onResume 延迟加载调度器相关加载
评论页面延迟表情在点击表情时加载
针对ListView的性能优化
1、复用convertView:在getItemView中,判断convertView是否为空,如果不为空,可复用。
2、异步加载图片,item中如果包含有image,那么最好异步加载。
3、快速滑动时不显示图片:当快速滑动列表时(SCROLL_STATE_FLING),item中的图片或获取需要消耗资源的view,可以不显示出来;而处于其他两种状态(SCROLL_STATE_IDLE和SCROLL_STATE_TOUCH_SCROLL),则将那些view显示出来。
4、item尽可能地减少使用的控件和布局的层次。同时要尽可能地复用控件,这样可以减少ListView的内存使用,减少滑动时gc次数。ListView的背景色与cacheColorHint设置相同颜色,可以提高滑动时的渲染性能。
5、getView优化:ListView中getView是性能是关键,这里要尽可能地优化。getView方法中不能做复杂的逻辑计算,特别是数据库和网络访问操作,否则会严重影响滑动时的性能
工具
1、开发者选项,GPU呈现模式分析
2、开发者选项,调试GPU过度绘制
3、Android Studio Profiler,可查看应用的cpu、内存、网络等状态,通过cpu可以查看到相关操作的函数调用过程和耗时。
4、ddms 里的Traceview,寻找卡住主线程的
5、Lint扫描 (移动app性能评测152)
6、性能分析报告 http://172.16.1.89:8000/talk/view?vid=1670#
推荐书籍:
《移动App性能评测与优化》
《Android移动性能实战》