为什么使用 Bundle 而不使用 HashMap

2,078 阅读5分钟

Hi 大家好,我是 DHL,大厂程序员,公众号:ByteCode ,在美团、快手、小米工作过。搞过逆向,做过性能优化,研究过系统,擅长鸿蒙、Android、Kotlin、性能优化、职场分享。

微信小程序「猿面试」每日分享一道大厂面试题,涉及 JavaAndroid鸿蒙和ArkTS设计模式算法和数据结构 等内容。


为什么使用 Bundle 而不使用 HashMap

Bundle 内部是由 ArrayMap 实现的,ArrayMapHashMap 是 Android 中常用的两种键值对数据结构,关于它们的区别可以前往微信小程序「猿面试」中查看 「ArrayMap和HashMap的区别」。

这篇文章我们一起来看一下在 Android 中为什么使用 Bundle 而不使用 HashMap。

Bundle 相比 HashMap 占用更少内存

Bundle 内部是由 ArrayMap 实现的,ArrayMap 的内部实现是两个数组,一个记录所有 key 的 hashcode 值组成的数组,是从小到大的排序方式,一个存放 key-value。

内部使用二分法进行查找,时间复杂度为 O (log n),但由于数组操作(如插入、删除)需要移动元素,插入和删除的时间复杂度为 O (n),因此只适合于小数据量操作。

ArrayMap 满足条件会扩容后的大小为原来的 1.5 倍,并且有容量收缩机制,当内存使用量不足 1/3 的情况下,内存数组会收紧 50%。

HashMap(1.8)内部则是数组 + 链表 + 红黑树结构,默认大小为 16,超过容量 3/4 的时候,双倍扩容,且没有容量收缩机制,所以占用内存更多,因此 ArrayMapHashMap 占用更少的内存。

系统的限制

Activity 之间通过 Intent 传递数据,因为其内部使用了 Binder 通信机制。

由于系统的限制,Binder 事务缓冲区的大小限定在 1MB,这个大小是共享的,所以不能传递大数据,因此使用 Bundle 来传递数据,可以保证更快的速度和更少的内存占用。

Parcelable 比 Serializable 性能更好

HashMap 使用 Serializable 进行序列化,而 Bundle 则是使用 Parcelable 进行序列化。

Serializable

Serializable 是 Java 原生序列化的方式,主要通过 ObjectInputStreamObjectOutputStream 来实现对象序列化和反序列化。

在整个过程中用到了大量的反射和临时变量,会频繁的触发 GC,序列化的性能会非常差。

序列化时需要手动指定 serialVersionUID,用来辅助序列化和反序列化过程的,序列化与反序列化的 serialVersionUID 必须相同才能够使序列化操作成功,如果不显式声明 serialVersionUID,类的任何细节改变,都可能改变默认的 serialVersionUID 这可能导致反序列化失败。

Parcelable

Parcelable 是为了解决了在 Android 中跨进程通信性能差的问题,Parcelable 写入和读取的时候都是采用自定义序列化存储的方式,不需要使用反射来推断它,因此 ParcelableSerializable 要快很多。

虽然性能得到提升,但是使用起来比 Serializable 要复杂,因此系统封装了 Bundle 类,方便我们进行数据的传输。

如何选择 Parcelable 比 Serializable

Serializable 的设计初衷是为了序列化对象到本地文件、数据库、网络流、RMI 以便数据传输,当然这种传输可以是程序内的也可以是两个程序间的。

而 Android 的 Parcelable 的设计初衷是由于 Serializable 效率过低,消耗大,而 Android 中数据传递主要是在内存环境中(内存属于 Android 中的稀有资源),因此 Parcelable 的出现为了满足数据在内存中低开销而且高效地传递问题。

因此 Android 应用程序在内存间数据传输时推荐使用 Parcelable

如果数据持久化存储,推荐使用 Serializable 更加方便,因为 Parcelables 与数据存储一起使用是不安全的,因为数据格式可能会在 Android 版本之间改变。因此在序列化到存储设备或者网络传输方面还是尽量选择 Serializable 接口

更多大厂面试题,欢迎前往微信搜索小程序 「猿面试」 查看。微信小程序 (猿面试) 包含了 Java、Android、鸿蒙和ArkTS设计模式算法和数据结构 相关内容,

更多面试题