前言
原来我的代码写得这么烂!
为什么优化
卡顿现象, 由于复杂的布局或界面过度绘制未能在每帧 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://www.bubuko.com/infodetail-2659154.html