Android的UI卡顿
Posted 呼啸
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android的UI卡顿相关的知识,希望对你有一定的参考价值。
这篇文章我们主要从3个方面分析:
1.UI卡顿的原理
2.UI卡顿的原因分析
3.卡顿的总结
来看第一部分,UI卡顿的原理:
先来看下这样一个数字;
60fps -> 16ms
其实用户所感受到的卡顿的问题主要是来源于安卓的渲染性的问题。
我们的UI设计师,总是希望我们的UI有非常绚丽的动画,非常精美的设计。经常使用一些非常大的图片来展示时尚的元素。但是UI设计师是站在UI设计师的角度来考虑问题。她们不知道安卓系统可能无法完成那些复杂的界面渲染操作。
我们知道安卓的系统每隔16ms会发出信号触发对UI进行渲染。
如果每次渲染都能成功,这样就能达到流畅的画面所需要的60fps,也就是每秒60帧。这就意味着程序的大多数操作必须在16MS内来完成。也就是拿1000/60约等于16ms。在执行一些动画,或者大家常见的Listview滑动的时候,我们通常会感觉到有时会有一些卡顿,没有那么流畅。这就是因为这里的操作很复杂,然后产生了丢帧现象。最终导致了卡顿。其实有很多原因都会造成卡顿。就拿listview来说,如果listview的Item的layout如果太过复杂,它就无法完成在16ms内的渲染。也有可能是你的Item层叠了太多的background,它太多的imageview,甚至有可能是动画执行的次数过多。这些都会造成CPU和GPU的复杂过重。
为什么要把标准设置在60fps,首先我们需要知道人眼对于画面的连续性他是有一定的限制性的。对于手机来说,我们需要感知屏幕的连贯性,我们就必须在这16ms内处理完所有的cpu的计算以及GPU的渲染操作。所以说,其实UI的卡顿是可以量化的。每一次能否成功渲染是非常重要的。
同时我们需要知道每一次GC的时候,所有的线程都会暂停。等GC完了之后,所有的线程才能继续执行。也就是说,如果这个16ms内正在渲染的时候,正好遇到了大量的GC操作。这就会导致渲染时间不够。从而导致卡顿。所以对于对象内存的分配,需要谨慎考虑。
接下来我们来看UI卡顿的第二个概念:
overdraw
中文意思是过度绘制。
啥意思,就是在屏幕上某一帧的像素在屏幕上被绘制了很多次。经常出现在多层次的UI结构里。
如果有时候你把UI设置成invisible或者gone的时候,它也会做绘制的操作。
这就导致某些绘制区被绘制很多次。这样就浪费了CPU和GPU的资源。
在开发过程中,如果老大让你解决UI卡顿问题,你可以用手机当中的GPU选项,在开发者选项中,大家可以观察,overdraw的情况。有蓝色,淡绿色,淡红色等。我们的目标就是减少红色,尽量出现蓝色。
overdraw出现的原因也就是说你的UI布局中,有大量重叠的部分。
还有些时候,是一些非必要的重叠背景。
举个例子,比如在activity中他有自己的背景,如果这个layout又有自己的背景。同时这个layout的子view又有自己的背景。这个时候,仅仅是通过移除非必须的背景图片就能减少红色的overdraw。
总结UI卡顿的原理,这些性能的问题,主要主要的根源就是来自安卓系统的渲染性,做了太多耗时操作。
做太多耗时操作的原因,有可能是你的layout太复杂,也有可能是你的layout上层叠了太多其他的UI布局。还有就是你的动画,执行次数过多。
分析了UI卡顿的原理之后,我们来进行第二个部分,UI卡顿的原因分析。
1.人为的在主线程中做了轻微的耗时操作,导致了UI线程的卡顿。
2.布局Layout过于复杂,无法在16ms内完成渲染。
3.同一时间,动画执行的次数过多,导致了CPU和GPU的负载过重。
4.View的过度绘制,导致某些像素在同一时间内被绘制了很多次,从而使CPU或GPU负载过重。
5.View频繁的触发measure,layout。导致measure,layout累计耗时过多,以及整个view频繁的重新渲染。
6.内存频繁触发GC过多,导致暂时阻塞渲染操作。
7.冗余资源以及逻辑等导致加载和执行缓慢。
UI卡顿的优化总结
1.布局优化
我们可以使用常见的include,mearge,viewstub标签。这在google提供给我们的官方文档上都有。
include就是直接使用布局嵌套来重用。mearge就是减少布局嵌套。
viewstub默认是一个不可见的,高度为0,只有在运行的时候才加载,也就是懒加载的组件。
viewstub默认是gone,高度为0,此时也不会绘制。需要显示的时候,需要调用setvisibility或者inflate才会加载。
使用:
<ViewStub
android:id="@+id/vs_test"
android:layout_width="200dp"
android:layout_height="200dp"
android:inflatedId="@+id/vs_inflate"
android:layout="@layout/viewstub_item" />
其中的layout:
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/lv_test"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
需要的时候才会加载:
ViewStub viewStub = findViewById(R.id.vs_test);
// 加载
viewStub.setVisibility(View.VISIBLE);
// 通过inflatedId获取viewstub_item里面的listView
ListView listView = findViewById(R.id.vs_inflate);
总结下就是
1.尽量不要多层嵌套,如果layout比较复杂的时候,可以考虑使用自定义view来实现。
2.列表和adapter优化
在滑动的时候,不要进行元素的更新。
3.背景和图片等的内存分配优化
尽量减少不必要的背景图
图片尽量要压缩。
4.避免ANR
以上是关于Android的UI卡顿的主要内容,如果未能解决你的问题,请参考以下文章