IOS现成的API里的json解析速度非常快,这里就不说了,今天对比一下Android里面json的解析库。
首先第一个是Android API里面自带的json解析,其次是谷歌提供的Gson解析库(开源),其次是在网上看到的解析很快速的阿里巴巴分享的Fastjson包。Android自带的json解析大家一定都很熟悉了,这里不介绍了,这里详细说说谷歌提供的另一套解析库Gson:
gson的使用方法非常的简单。只需要将需要解析的json字符串和对应的Bean类xing型传递给GSON类的from方法既可:
Gson gson = new Gson(); List<StatusObject> so = gson.fromJson(mJsonString, new TypeToken<List<StatusObject>>() {}.getType());
这里的beanlei类中的字段的命名要和json中的字段相同,其次实现get和set方法(稍后讲原因)。
标准的bean:
import java.util.List; public class Geo { private String type; private List<Float> coordinates; public Geo() {} public String getType() { return type; } public void setType(String type) { this.type = type; } public List<Float> getCoordinates() { return coordinates; } public void setCoordinates(List<Float> coordinates) { this.coordinates = coordinates; } }
我曾经担心复杂的json结构会不会解析出现问题,但是试验了以后嵌套了其他的bean类,照样迭代赋值了。
阿里巴巴提供的fastjson库使用方法和gson一样,只是底层的原理不同。这里不详细介绍了。
下面看一下三个库解析相同的json字段的对比:(使用了25条非常复杂的Json数据)
大家可以看到谷歌提供的gson有非常大的速度优势。这里我们走进它的代码浏览一下。
找到了关键的类:JsonObject.java
package com.google.gson; import com.google.gson.internal.LinkedTreeMap; import java.util.Map.Entry; import java.util.Set; public final class JsonObject extends JsonElement { private final LinkedTreeMap<String, JsonElement> members = new LinkedTreeMap(); JsonObject deepCopy() { JsonObject result = new JsonObject(); for (Map.Entry entry : this.members.entrySet()) { result.add((String)entry.getKey(), ((JsonElement)entry.getValue()).deepCopy()); } return result; } public void add(String property, JsonElement value) { if (value == null) { value = JsonNull.INSTANCE; } this.members.put(property, value); } public JsonElement remove(String property) { return (JsonElement)this.members.remove(property); } public void addProperty(String property, String value) { add(property, createJsonElement(value)); } public void addProperty(String property, Number value) { add(property, createJsonElement(value)); } public void addProperty(String property, Boolean value) { add(property, createJsonElement(value)); } public void addProperty(String property, Character value) { add(property, createJsonElement(value)); } private JsonElement createJsonElement(Object value) { return value == null ? JsonNull.INSTANCE : new JsonPrimitive(value); } public Set<Map.Entry<String, JsonElement>> entrySet() { return this.members.entrySet(); } public boolean has(String memberName) { return this.members.containsKey(memberName); } public JsonElement get(String memberName) { return (JsonElement)this.members.get(memberName); } public JsonPrimitive getAsJsonPrimitive(String memberName) { return (JsonPrimitive)this.members.get(memberName); } public JsonArray getAsJsonArray(String memberName) { return (JsonArray)this.members.get(memberName); } public JsonObject getAsJsonObject(String memberName) { return (JsonObject)this.members.get(memberName); } public boolean equals(Object o) { return (o == this) || (((o instanceof JsonObject)) && (((JsonObject)o).members.equals(this.members))); } public int hashCode() { return this.members.hashCode(); } }
可以看到其中使用了一个LinkedTreeMap来缓存字段与值。这里要比我们直接使用API中的方法寻找要快,其次在类ProtoTypeAdapter.java中我们找到了赋值方法:
@SuppressWarnings("unchecked") @Override public GeneratedMessage deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { JsonObject jsonObject = json.getAsJsonObject(); Class<? extends GeneratedMessage> protoClass = (Class<? extends GeneratedMessage>) typeOfT; try { // Invoke the ProtoClass.newBuilder() method Object protoBuilder = getCachedMethod(protoClass, "newBuilder") .invoke(null); Class<?> builderClass = protoBuilder.getClass(); Descriptor protoDescriptor = (Descriptor) getCachedMethod( protoClass, "getDescriptor").invoke(null); // Call setters on all of the available fields for (FieldDescriptor fieldDescriptor : protoDescriptor.getFields()) { String name = fieldDescriptor.getName(); if (jsonObject.has(name)) { JsonElement jsonElement = jsonObject.get(name); String fieldName = name + "_"; Field field = protoClass.getDeclaredField(fieldName); Type fieldType = field.getGenericType(); Object fieldValue = context.deserialize(jsonElement, fieldType); Method method = getCachedMethod( builderClass, "setField", FieldDescriptor.class, Object.class); method.invoke(protoBuilder, fieldDescriptor, fieldValue); } } // Invoke the build method to return the final proto return (GeneratedMessage) getCachedMethod(builderClass, "build") .invoke(protoBuilder); } catch (SecurityException e) { throw new JsonParseException(e); } catch (NoSuchMethodException e) { throw new JsonParseException(e); } catch (IllegalArgumentException e) { throw new JsonParseException(e); } catch (IllegalAccessException e) { throw new JsonParseException(e); } catch (InvocationTargetException e) { throw new JsonParseException(e); } } catch (Exception e) { throw new JsonParseException("Error while parsing proto: ", e); } }
这里通过反射类的set方法来给变量赋值,因此bean类中的变量要加上get和set方法。
文章出处: http://android-study.diandian.com/post/2013-07-11/40050907908