读书笔记5-数据存储篇

679 阅读5分钟

本系列博文 基于是前微信高级工程师张绍文专栏 《Android开发高手课》的读书笔记。

文章所写内容是本人读完的感悟,需要原文的朋友请自行购买。

存储优化篇

Android分区

分区简单来说就是将设备中的存储划分为一些互不重叠的部分,每个部分都可以单独格式化,用作不同的目的。

  • /system: 操作系统预留,用来存储系统文件和框架的,系统升级和恢复时会擦除这一整块分区
  • /data: 用来存储用户数据的地方,手机上恢复出厂设置的那个操作就只会擦除这部分数据
  • /cache: 系统升级或者恢复时的备用分区
  • /vendor: 用来存放手机厂商对Android系统的修改
  • /storge: 内置或者外置的sdcard

数据存储需要考虑哪些要素

数据存储就是把特定的数据结构转化成可以被记录和还原的格式,这个数据格式可以是二进制的,也可以是 XML、JSON、Protocol Buffer 这些格式。

在选择数据存储的时候需要考虑的要素

数据存储的选项

  • SharedPreferences
  • ContentProvider
  • 文件
  • 数据库

SharedPreferences

使用场景

用于存储一些非常简单,轻量的数据。

优点

  • 系统支持,使用简单
  • 兼容性强

缺点

  • 跨进程不安全
  • 加载缓慢。SharedPreferences 文件的加载使用了异步线程,而且加载线程并没有设置线程优先级,如果这个时候主线程读取数据就需要等待文件加载线程的结束
  • 全量写入。无论是调用 commit() 还是 apply(),即使我们只改动其中的一个条目,都会把整个内容全部写到文件。而且即使我们多次写入同一个文件,SP 也没有将多次修改合并为一次,这也是性能差的重要原因之一。

基于以上原因,各大公司都会有对应的一个替代的存储方案,比如微信的MMKV

ContentProvider

使用场景

跨进程,跨应用程序之间的大数据量交互,总体来说ContentProvider的整体框架还是不错的,目前市面上好像也没有什么自研的架构替代。

需要注意的点

ContentProvider 的生命周期默认在 Application onCreate() 之前,而且都是在主线程创建的。我们自定义的 ContentProvider 类的构造函数、静态代码块、onCreate 函数都尽量不要做耗时的操作,会拖慢启动速度。

对象的序列化

Serializable

java原生的序列化机制,其本身是通过 ObjectInputStream 和 ObjectOutputStream 来实现的,由于在序列化过程中使用了大量的反射和临时变量使得性能下降,文件体积变大。

需要注意的点

  • 不被序列化的字段。类的 static 变量以及被声明为 transient 的字段,默认的序列化机制都会忽略该字段,不会进行序列化存储。当然我们也可以使用进阶的 writeReplace 和 readResolve 方法做自定义的序列化存储。
  • serialVersionUID。在类实现了 Serializable 接口后,我们需要添加一个 Serial Version ID,它相当于类的版本号。这个 ID 我们可以显式声明也可以让编译器自己计算。通常我建议显式声明会更加稳妥,因为隐式声明假如类发生了一点点变化,进行反序列化都会由于 serialVersionUID 改变而导致 InvalidClassException 异常。
  • 构造方法。Serializable 的反序列默认是不会执行构造函数的,它是根据数据流中对 Object 的描述信息创建对象的。如果一些逻辑依赖构造函数,就可能会出现问题,例如一个静态变量只在构造函数中赋值,当然我们也可以通过进阶方法做自定义的反序列化修改。

Parcelable

主要解决Serializable性能低下的问题。

使用Parcelable比Serializable需要多添加一些自定义代码,正是因为这些代码,使得Parcelable在序列化的时候不需要采用大量反射这种耗时的行为,从而提高性能。

需要注意的点

使用Parcelable进行永久存储的话,会存在一些问题。

  • 系统版本的兼容性。由于 Parcelable 设计本意是在内存中使用的,我们无法保证所有 Android 版本的Parcel.cpp实现都完全一致。如果不同系统版本实现有所差异,或者有厂商修改了实现,可能会存在问题。
  • 数据前后兼容性。Parcelable 并没有版本管理的设计,如果我们类的版本出现升级,写入的顺序及字段类型的兼容都需要格外注意,这也带来了很大的维护成本。

一般来说,如果需要持久化存储的话,一般还是不得不选择性能更差的 Serializable 方案。

Serial

Twitter开源的Serial保留了Serializable和Parcelable的大部分优点

数据的序列化

Serial 性能看起来还不错,但是对象的序列化要记录的信息还是比较多,在操作比较频繁的时候,对应用的影响还是不少的,这个时候我们可以选择使用数据的序列化。

JSON

优点

  • 相比对象序列化方案,速度更快,体积更小。
  • 相比二进制的序列化方案,结果可读,易于排查问题。
  • 使用方便,支持跨平台、跨语言,支持嵌套引用。

市面上可用的框架有Android自带的JSON库,Google的Gson,阿里的FastJson,美团的MSON

总的来说Gson的兼容性最好,数据量极大时,FastJson的性能最佳。

Protocol Buffers

二进制序列化方案,数据量庞大的时候性能优于JSON,

数据库优化

推荐使用自带的SQLite,Realm或者Google的LevelDB。

这部分内容在张老师文中提到的多是线程并发,索引优化,page和缓存处理等。比较深,这里就不提了。