问题
我们经常需要在主线程中读取一些配置文件或者缓存数据,最常用的结构化存储数据的方式就是将对象序列化为JSON字符串保存起来,这种方式特别简单而且可以和SharedPrefrence配合使用,因此应用广泛。但是目前用到的Gson在序列化JSON时很慢,在读取解析这些必要的配置文件时性能不佳,导致卡顿启动速度减慢等问题。
Gson的问题在哪里呢?笔者用AndroidStudio的profile工具分析了activity.onCreate方法的耗时情况。
![lifecycle-analyse.jpg](https://i-blog.csdnimg.cn/blog_migrate/776327c0636df1a64835f31db7c7f815.png)
![lifecycle-analyse2.jpg](https://i-blog.csdnimg.cn/blog_migrate/7038b7b71a2498742c8163a23c25e7f6.png)
如图1,可以发现Gson序列化占用了大部分的执行时间,从图2可以更直观地看到Gson.fromJson占用了61%的执行时间。分析Gson的源码可以发现,它在序列化时大量使用了反射,每一个field,每一个get、set都需要用反射,由此带来了性能问题。
如何优化
知道了性能的瓶颈之后,我们如何去修改呢?我能想到的方法就是尽量减少反射。
Android框架中由JSONObject来提供轻量级的JSON序列化工具,所以我选择用Android框架中的JSONObject来做序列化,然后手动复制到bean就可以去掉所有的反射。
我做了个简单的测试,分别用Gson和JSONObject的方式去序列化一个bean,看下各自速度如何。
使用JSONObject的实现方式如下:
public class Bean {
public String key;
public String title;
public String[] values;
public String defaultValue;
public static Bean fromJsonString(String json) {
try {
JSONObject jsonObject = new JSONObject(json);
Bean bean = new Bean();
bean.key = jsonObject.optString("key");
bean.title = jsonObject.optString("title");
JSONArray jsonArray = jsonObject.optJSONArray("values");
if (jsonArray != null && jsonArray.length() > 0) {
int len = jsonArray.length();
bean.values = new String[len];
for (int i=0; i<len; ++i) {
bean.values[i] = jsonArray.getString(i);
}
}
bean.defaultValue = jsonObject.optString("defaultValue");
return bean;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
public static String toJsonString(Bean bean) {
if (bean == null) {
return null;
}
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("key", bean.key);
jsonObject.put("title", bean.title);
if (bean.values != null) {
JSONArray array = new JSONArray();
for (String str:bean.values) {
array.put(str);
}
jsonObject.put("values", array);
}
jsonObject.put