我第一次知道FlatBuffers是因为Facebook写的 这篇Android的技术博客文章 。它主要介绍了FlatBuffers对比JSON的优势,以及Facebook Android App应用了FlatBuffers后,衍生的数据和界面更新的工作流转模式。建议去读一读,作者还是一个中国人哦。
下面开始介绍了一下FlatBuffers,首先看看它和JSON的对比。
先引用 GitHub frogermcs/FlatBuffs 上的两张Gif效果图.
那个Loading菊花是干什么的呢?点击上下两个按钮开始数据解析,而数据解析是故意放在主线程上执行,而Loading菊花能直观的辨别解析过程有没有导致UI卡顿。
左图,点击"PARSE JSON"按钮是用的 Gson 解析了一个468KB的Json文件,耗时200-300ms。
右图,点击"USE FLATBUFFERS",是“解析”同样的Json数据但是用FlatBuffers特有的数据格式文件repos_flat.bin。耗时是<10ms。FlatBuffers“解析”的过程,Loading菊花一直保持着流畅的转动。
FlatBuffers到底有什么样的魔术,能比JSON快这么多呢?
其实FlatBuffers实际并没有做数据的解析,repos_flat.bin是按照FlatBuffers数据组织格式生成的Byte数组。
FlatBuffer的数据解析是靠一层层的offset偏移量的组合计算定位到数据在Byte数组的位置,进而获取目标数据的值 。所以FlatBuffer是需要什么数据,才解析什么数据,并不需要全量解析。
简单说,FlatBuffers分为vtable区和数据区。vtable区保存的是数据的偏移值,数据区保存的是具体的数据值。
FlatBuffers的优点和缺点
优点:
1. 数据都是从Byte数组中获取,减少解析过程的内存占用,减低了GC发生概率。
Memory Efficient Serialization Library,FlatBuffers是这么描述自己的。
这里有别人做的内存检测的数据 。
2. 无需全量解析,用到的数据才需要解析。
想象一个很长的ListView,并不需要在初始状态就把所有的数据都解析出来。滚动到可见状态的item的数据,才需要被解析。
缺点:
1. 数据获取都是偏移量计算的解析过程,嵌套层级深的数据,可能带来性能问题。
2. 不自行做数据缓存的话,每次获取同样的数据会有重复计算。
3. Byte数据安全性和完整性有顾虑。也有人专门写 博客表明不会用FlatBuffer 哈哈。
FlatBuffers的应用
FlatBuffers还可以“解析”JSON,实际是把JSON数据生成FlatBuffers格式的Byte数组。
如上图,中间的按钮“PARSE JSON(FLATBUFFERS)”点击执行后解析468KB同样的JSON文件,比Gson节省了约40%的耗时。
作为应用FlatBuffers的切入点,参考着的 frogermsc GitHub Demo ,我尝试把FlatBuffer解析JSON应用到工作项目中。
步骤:
1. 使用FlatBuffers需要引入2个SO和一个JAR,合计1MB;
2. 根据待解析的数据,要写一个schema文件如下,类似于protocolBuffer的.proto文件的作用;
namespace RankDetail; table RankDetail { code : int; msg : string; } root_type RankDetail;
3. 通过命令行,根据schema生成相关解析后数据读取的Java类,这个步骤也类似protocolBuffer;
遇到的问题:
1. schema文件的Key-value对的Key不能数字开头,如下的123key是不符合要求的;
原因是因为,FlatBuffers是直接获取schema文件内的这种key-value的key的值作为方法名字和变量名字,阿拉伯数字开头的变量名和方法名是不合法的。
namespace RankDetail; table RankDetail { code : int; msg : string; 123key : string; } root_type RankDetail;
2. 解析是在SO的native代码,遇到失败就会native crash,缺少有用的解析失败的日志信息,增加开发调试的难度和时间。
FlatBuffers最大的威力是解析他自家格式的Byte数组(参考文章开头的GIF对比),应用到正式环境的功能,需要后台请求返回的数据是FlatBuffers格式的Bytes数组。另外,FlatBuffers解析的容错性目前还有待完善提升。但以后,FlatBuffers会是减少内存占用、提升用户体验的利器。