卡顿分享

卡顿分享

  1. 什么是卡顿
  2. 如何衡量卡顿
  3. 产生卡顿的原因
  4. 卡顿优化
  5. 工具使用

什么是卡顿

卡顿是人的一种视觉感受,比如我们滑动界面时,如果滑动不流畅我们就会有卡顿的感觉,这种感觉我们需要有一个量化指标,在编程时如果开发的程序超过了这个指标我们认为其是卡顿的。

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

 

  1. 将可复用的组件抽取出来并通过include标签使用。
  2. 使用ViewStub标签来加载一些不常用的布局。

不常用的UI经常被设置成了GONE,比如error页面,断网页面,如果有这类问题,我们可以用<ViewStub/>标签代替GONE提高UI性能。<ViewStub/>标签是当你需要时才会加载,使用它并不会影响UI初始化时的性能。以减少内存使用量,加快渲染速度。

4、使用merge标签减少布局的嵌套层次。https://www.jianshu.com/p/69e1a3743960

  1. 包含ImageView和TextView的LinearLayout可以使用包含图片的Textview这样更高效。
  2. 内嵌使用包含layout_weight属性的LinearLayout会在绘制时消耗系统资源,因为每一个子组件都需要被测量两次。在使用ListView与GridView的时候这个问题显得尤其重要,因为子组件会重复被创建,所以要尽量避免使用Layout_weight。
  3. 尽可能少用wrap_content。wrap_content 会增加布局 measure 时计算成本,在已知宽高为固定值时,不用wrap_content 。
  4. 删除控件中无用的属性。

9、无用的命名空间。

避免过度绘制

Overdraw(过度绘制)描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次(至少两次)。在多层次的UI结构里面,如果不可见的UI也在做绘制的操作,这就会导致某些像素区域被绘制了多次这就浪费大量的CPU以及GPU资源。

我们可以通过手机设置里面的开发者选项,打开“调试GPU过度绘制”选项,可以观察UI上的过度绘制情况。

我们的目标就是尽量减少红色区域,看到更多的蓝色区域。

如何避免过度绘制,如下:

  1. 移除 XML 中非必须的背景,有多层背景颜色的Layout来说,留最上面一层的颜色即可,其他底层的颜色都可以去掉
  2. 移除 Window 默认的背景、按需显示背景图片

 

  1. 自定义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过度绘制

3Android Studio Profiler,可查看应用的cpu、内存、网络等状态,通过cpu可以查看到相关操作的函数调用过程和耗时

4、ddms 里的Traceview,寻找卡住主线程的

5、Lint扫描 (移动app性能评测152)    

6、性能分析报告 http://172.16.1.89:8000/talk/view?vid=1670#

                                                                 

推荐书籍:

移动App性能评测与优化

《Android移动性能实战》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值