Fork me on GitHub

这可能是最好的性能优化教程(一)

这可能是最好的性能优化教程系列专栏
这可能是最好的性能优化教程(一)
这可能是最好的性能优化教程(二)
这可能是最好的性能优化教程(三)

前言

性能检测与分析,一直在 APP 开发中相当重要,但又被我们常常忽略。很多 APP 或者开发者总是急功近利,总想着快速充实 APP 的相关功能,把开发进度放在首位没有问题,可很多时候就没有然后了,这在整个开发界屡见不鲜。

在这样的大背景下,加之我之前写的 RxJava 2.0 系列 收到较好的反馈,诱导我想出这么一个性能优化系列。

一些你可能需要知道的

了解我的知道,我出的系列基本都是比较基础,而且侧重于常见必备。所以不一定全面,也不一定深入,所以希望理解。

性能优化大概可以概括为:

  • 性能优化说起来很简单,但做起来难。
  • 性能优化点多并且繁杂,需要耐心和经验。也许每个优化点很小,但积累起来会从量变变成质的飞跃。
  • 性能优化必须建立在产品设计之上,不能为了追求性能而忽略了产品设计。

提供一些资源 ( 你可能需要梯子 )

善用 ArrayMap

程序内存的管理是否合理高效对应用的性能有着很大的影响,有时候对容器的使用不当也会导致内存管理效率低下。想必已经有很多童鞋知道了 SparseArray,但它只是用于替代 List。

我们经常会在程序中用到 HashMap,它非常好用,这毋庸置疑。但它却非常耗内存。HashMap 的工作原理这里我们就不讲了,有兴趣的自行科普。

更高效的 ArrayMap 容器

为了解决 HashMap 更占内存的弊端,Android 提供了内存效率更高的 ArrayMap。它内部使用两个数组进行工作,其中一个数组记录 key hash 过后的顺序列表,另外一个数组按 key 的顺序记录 Key - Value 的值。如下图所示:

当你想获取某个 Value 的时候,ArrayMap 会计算输入 key 转换过后的 hash 值,然后对 hash 数组使用二分查找法寻找到对应的 index,然后我们可以通过这个 index 在另外一个数组中直接访问到需要的键值对。如果在第二个数组键值对中的 key 和前面输入的查询 key 不一致,那么就认为是发生了碰撞冲突。为了解决这个问题,我们会以该 key 为中心点,分别上下展开,逐个去对比查找,直到找到匹配的值。如下图所示:

随着数组中的对象越来越多,查找访问单个对象的花费也会跟着增长,这是在内存占用与访问时间之间做权衡交换。

既然ArrayMap中的内存占用是连续不间断的,那么它是如何处理插入与删除操作的呢?请看下图所示,演示了Array的特性:


很明显,ArrayMap 的插入与删除的效率是不够高的,但是如果数组的列表只是在一百这个数量级上,则完全不用担心这些插入与删除的效率问题。HashMapArrayMap 之间的内存占用效率对比图如下:

HashMap 想必,ArrayMap 在循环遍历的时候也更加简单高效,因为其采用的是 fori 循环,而 HashMap 却使用的是糟糕的 Iterator

并不是所有情况下都用 ArrayMap

ArrayMap 这么优秀,但并不是所有情况下都适合使用 ArrayMap,我们应该在满足下面两个条件的时候才考虑使用 ArrayMap

  • 对象个数的数量级最好在 1000 以内。
  • 数据组织形式包含 Map 结构。

所以我们需要学会在特定清醒下选择相对更加高效的实现方式。

UI 性能确实很重要

UI 界面是整个 APP 性能的最前端展示,也是最容易看出性能问题的地方。可以毫不夸张地说,UI 性能的好坏直接影响这用户的体验和留存。UI 性能的目标是:

  • 减少绘图的等待时间。
  • 使帧率更加平稳、连贯。

UI 布局的核心原则

核心原则一句话,尽可能地减少 View 的数量!

我们可以通过 includemergeviewstub 进行布局复用,通过控件属性 DrawableLeft、DrawableRight 等方式进行控件整合。

听说我们要尽可能地用 RelativeLayout ?

想必一些资历较老的 Android 开发者都知道,一开始系统默认创建的布局是 LinearLayout,后面替换成了 RelativeLayout,现在又变成了 ConstraintLayout 。由于我对 ConstraintLayout 不是特别了解,所以这里我着重说说 RelativeLayout 和 LinearLayout 。

我不知道在什么时候听说过,如果我们能用 RelativeLayout 的地方,尽量不要用 LinearLayout

这种说法是不对的,实际开发中,决不能简单地说 RelativeLayout 和 LinearLayout 谁的性能更好,必须结合实际使用来进行分析。

基本可以总结为:一般情况下,如果使用 LinearLayout,则一定要保证层级不能太深;如果使用 RelativeLayout,则需要尽量避免嵌套。

后记

以上便是本期内容,由于楼主也是开发任务很多,所以只能在有空的时候更新,如果想第一时间收到更新信息的请关注我的公众号:nanchen