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