原来,一直是JSON在挖坑

Posted 安卓巴士Android开发者门户

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原来,一直是JSON在挖坑相关的知识,希望对你有一定的参考价值。

点击上方“安卓巴士android开发者门户”即可关注!


最近发现自家的Android app在使用过程中并没有传说当中的“如黄油般顺滑”,而且通过查看logcat发现app会频繁地发起 GC_FOR_ALLOC 调用,Activity和Fragment之间的跳转也没有想象当中那样快。于是好学的工程师们开始去挖掘这个背后的内容。


一切都是JSON解析挖的坑

通过初步的性能测试,我们发现以上现象的很大部分原因来自于app在解析JSON的时候耗时过多。于是我们决定深入去看看app的JSON解析代码有些什么问题?Foursquare的Android应用都是通过一个 JSON API来同服务器进行交互的,JSON的解析则是使用Google的 Gson 库,也就是说使用Gson来反序列化JSON字符串生成相应的Java对象供Android开发者进行下一步处理。我们一般是这样使用Gson将一个描述venue(场地)的字符串转化成Java对象的:


原来,一直是JSON在挖坑


程序是这样没问题,可是实际上我们只需要venue的Name属性,但是上面的程序却解析了整个JSON字符串。是不是这里造成了一部分性能问题?如果我们只解析我们想要的属性,会不会降低JSON解析的时间?于是他们开始使用 Gson streaming API ,确保Android在解析JSON的时候省去了将Reader转化为String的步骤,直接解析Reader,示例代码如下:


原来,一直是JSON在挖坑


这下问题应该解决一大半了吧!NO!这样的改动并没有带来app在速度和流畅度上面的任何改进。到底是什么原因呢?我们最终发现问题在于我们使用了自定义的 Gson deserializer。由于我们在开发的时候常常发现JSON和这个JSON对于的Java对象并不是一一映射关系,于是我们使用了自定义的Gson deserializer在处理这样的问题,这里我们主要用到了JsonDeserializer 接口:


原来,一直是JSON在挖坑


你只需实现这个接口,告诉系统你所关注的type,接着你再把这个type同你要反序列化的Gson实例注册即可。接下来,如果你要将某个JSON字符串反序列化成某一个 Type typeOfT,那么Gson 就会在系统中检查是否存在相应的自定义deserializer 处理这个 typeOfT type 。如果存在这样的自定义deserializer ,那么系统便会调用这个自定义 deserializer的deserialize 方法。 我们在系统中为几种type自定义了deserializer ,其中一个就是最外层的 Response type ,它封装了所有 Foursquare API 的响应:


原来,一直是JSON在挖坑

改进方案

虽然我们使用了 Gson 的 streaming API,但是我们自定义的 deserializer 会把任何我们想要反序列化的JSON stream 都读进了一个JsonElement 对象树里面,然后这个JsonElement 再被传入 deserialize 方法 (然而这恰恰是我们要避免的情况)。更糟糕的是,我们从服务器接收到的每一个响应都会被包装成 response type ,这就阻碍了流式反序列化的进行( streaming deserialization)。最后的实践证明我们可以采取 TypeAdapters 和 TypeAdapterFactorys 方案来代替 JsonDeserializer。示例代码如下:


原来,一直是JSON在挖坑


我们从上面的代码可以发现 JsonReader stream 被直接传入 read() 方法而不是传入一个 JsonElement 树。通过上面的改进之后,即把我们自定义的 deserializer 改为继承 TypeAdapters 和 TypeAdapterFactorys ,我们app在解析大的响应的时候解析时间减少了 50% 以上。更重要的是,整个 app 感觉比以前要快多了,app的滑动也顺畅多了。



一些感悟
  • 尽量使用 GSON 的 streaming APIs,特别是在像Android这样的内存制约较多的平台上。 The memory savings for non-trivial JSON strings are significant.

  • 使用 TypeAdapters 实现的deserializer 代码肯定要比使用JsonDeserializers 实现的deserializer 代码要丑,因为TypeAdapters 比起JsonDeserializers 更偏向于底层了,或者说JsonDeserializers 要比TypeAdapters 更抽象一下,而越是底层的代码越具体。相应的JsonDeserializers 肯定也要比TypeAdapters 方案要灵活些。

  • 尽管存在这些缺点,但是很多时候代码的美观程度和灵活性相对于内存的使用,优先级还是要排在后面的

  • 尽可能少用自定义的 deserialization ,因为代码的复杂度增加了。


推荐

RxAndroid视频教学:



一周精选:



公众号ID:anzhuobashi
APKBUS是一家服务于中国移动开发者学习与成长需要的综合社区服务平台,专门为开发者提供最优质的资源服务、最完善的信息共享平台!合作请联系QQ:435399051~


点击“阅读原文”

以上是关于原来,一直是JSON在挖坑的主要内容,如果未能解决你的问题,请参考以下文章

json的细节

java处理json 的常用方式

用方括号括起来时 JSON 作为原始字符串?

python之装饰器生成器内置函数JSON

JSON-JSON字符串转换成JSON对象JSON对象数组java实体类以及保存到List列表中

原来 php 中的 json_encode() 只支持utf-8.不支持gbk啊