前言
原来我的代码写得这么烂!
为什么优化
卡顿现象,由于复杂的布局或界面过度绘制未能在每帧16ms内完成导致的。
复杂的布局
Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,要每次渲染都成功,这样就必须达到流畅的画面所需要的60fps,否则会发生丢帧的现象,丢帧越多,用户明确感到卡顿。
补充:
1、fps,每秒显示帧数,帧率测量单位(frames per second);
2、为什么是60fps(16ms=1000/60)?因为人眼与大脑之间的协作无法感知超过60fps的画面更新。
过度绘制
Overdraw(过度绘制)是指系统在单个渲染帧中多次绘制屏幕上的像素。例如,如果我们有一堆堆叠的UI卡,不可见的UI也在做绘制的操作,这样会浪费大量的CPU和GPU资源。
补充:
渲染操作通常依赖于两个核心组件:CPU与GPU。CPU负责包括Measure,Layout,Record,Execute的计算操作,GPU负责Rasterization(栅格化)操作。
如何检测
Show GPU Overdraw
打开Show GPU Overdraw选项进行观察是否存在过度绘制。
步骤:
设置 -> 开发者选项 -> 调试GPU过度绘制 ->显示过度绘制区域。
对比一张Overdraw的参考图,分别有蓝色,淡绿,淡红,深红代表了4种不同程度的Overdraw情况:
蓝色: 意味着overdraw 1倍,像素绘制了两次;
绿色: 意味着overdraw 2倍,像素绘制了三次;
淡红: 意味着overdraw 3倍,像素绘制了四次;
深红: 意味着overdraw 4倍,像素绘制了五次或者更多。
我们的目标就是尽量减少红色Overdraw,看到更多的蓝色区域。
Profile GPU Rendering
打开Profile GPU Rendering,显示每帧画面所需要渲染的时间。
步骤:
设置 -> 开发者选项 -> GPU呈现模式分析 -> 在屏幕上显示为条形图
界面上会滚动显示垂直的柱状图来表示每帧画面所需要渲染的时间,柱状图越高表示花费的渲染时间越长。中间有一根绿色的横线,代表16ms,我们需要确保每一帧花费的总时间都低于这条横线,这样才能够避免出现卡顿的问题。
Hierarchy Viewer
用Hierarchy Viewer工具检查Activity中的布局是否过于复杂
步骤:
Tools -> Android -> Android Device Monitor。
打开Hierarchy Viewe:
启动Android Device Monitor成功之后,在新的的窗口中点击切换视图图标,选择Hierarchy Viewe:
使用Hierarchy Viewer:
其实中带有红色或×××的点代表速度较慢的View。
友情提示:
APP先运行起来再使用Android Device Monitor,建议用模拟器,手机可能读不到内容。
TraceView
使用TraceView来观察CPU执行情况,使用详见:性能分析工具 Android TraceView。
优化
删除不必要的布局背景
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="?attr/backgroundColor" android:orientation="vertical"> <com.wuxiaolong.pullloadmorerecyclerview.PullLoadMoreRecyclerView android:id="@+id/pullLoadMoreRecyclerView" android:layout_width="match_parent" android:layout_height="match_parent"/></LinearLayout>
如果这里PullLoadMoreRecyclerView也设置背景色是没有必要了。
另外,使用Android一些自带的主题,window被默认添加一个纯色的背景,theme中添加android:windowbackground=”null”除掉或添加自己需要的背景色,减少渲染。
优化布局层次
通过优化视图层次结构,以减少重叠的UI对象的数量来提高性能。
这里得纠正我一个错误,我平时不想使用RelateLayout,是因为不想每个都命名id,命名是件很头疼的事,所以我更多使用了LinearLayout布局。为了提高性能,还是尽量多使用RelativeLayout吧。
使用include、merge、ViewStub
1、include布局重用;
2、merge减少视图层级;
3、ViewStub标签是当你需要时才会加载
详细介绍见:Android抽象布局——include、merge 、ViewStub
自定义组件的onDraw()
1、避免大量创建临时对象,比如String,以免频繁触发GC;
2、考虑使用canvas.clipRect()绘制需要被绘制的区域。
ListView
1、考虑使用ViewHolder;
2、或者RecycleView来代替
Lint
Lint是一个代码扫描工具,能够帮助我们识别代码结构存在的问题。在布局文件上运行lint工具来搜索可能的视图层次结构优化是一种很好的做法。
步骤:Android Studio,Analyze -> Inspect Code。
布局信息将显示在Android> Lint> Performance下:
要查看更多详细信息,您可以单击每个项目来展开它,并在屏幕右侧的窗格中查看更多信息。
lint规则:
Use compound drawables - A LinearLayout which contains an ImageView and a TextView can be more efficiently handled as a compound drawable.
Merge root frame - If a FrameLayout is the root of a layout and does not provide background or padding etc, it can be replaced with a merge tag which is slightly more efficient.
Useless leaf - A layout that has no children or no background can often be removed (since it is invisible) for a flatter and more efficient layout hierarchy.
Useless parent - A layout with children that has no siblings, is not a ScrollView or a root layout, and does not have a background, can be removed and have its children moved directly into the parent for a flatter and more efficient layout hierarchy.
Deep layouts - Layouts with too much nesting are bad for performance. Consider using flatter layouts such as RelativeLayout or GridLayout to improve performance. The default maximum depth is 10.
Lint除了layout优化,还能检查编码、可访问性等问题。
原文地址:http://blog.51cto.com/13807306/2132545