Android解析JSON,你真的需要三方庫?
一般情況下,如果伺服器返回 JSON 資料,而且你又是做 Android 的,那麼你首先想到的可能是GSON
,或是fastJson
這樣的框架。這些框架能夠很方便和快速的讓我們將 JSON 轉換成本地物件,是開發的首選。但是引用三方庫也是有代價的,顯而易見的就是包體積增大,庫的升級等。這個時候,就需要想一想我們是不是必須要使用三方庫了。
其實在 Android 上處理 JSON ,Google 已經給我們提供了一些類,而這些類滿足了大多數簡單的需求。如果我們只是需要對 JSON 進行簡單的解析處理,那麼完全可以避免引入第三方庫。
org.json
在Android的參考文件中,我們能發現一個包,名為:org.json
類名 | 描述 |
---|---|
JSONArray | A dense indexed sequence of values. |
JSONObject | A modifiable set of name/value mappings. |
JSONTokener | Parses a JSON (RFC 4627) encoded string into the corresponding object. |
關於 org.json
的程式碼,還可以在 https://github.com/stleary/JSON-java 上找到,而且裡面的類遠不止這4個,裡面很多內容都值得去探索一下。但是由於本文僅專注於在 Android 上利用此工具處理 JSON,所以就僅僅討論著四個類,下面將分別對著四個類逐一講解。
JSONObject
這個類是這四個類中最關鍵的一個,它表示了一個可更改且無序的鍵值對集合,更簡單一點,可以直接認為這個類表示了一個 JSON 的資訊。在 JSON 字串中,其表示了一個包裹在花括號的字串,鍵和值之間使用冒號隔開,鍵值和鍵值之間使用逗號隔開的。
在這個類中,其鍵名是唯一且不為null
的字串。而值則可以為 JSONObject
、JSONArray
、Strings
、Booleans
、Integers
、Longs
、Double
或者 JSONObject.NULL
。特別注意,這裡的NULL
可不是null
,而是JSONObject
的一個內部類。
對於這個類,在使用時要要注意的就是在呼叫時,其會按照呼叫的方法進行型別轉換。下面就介紹一下三類函式:
getXXX()
獲取一個值,此方法如果發生失敗,例如沒有找到對應的鍵值或型別轉換失敗,就會丟擲一個JSONException
異常;optXXX()
此類方法也是用於獲取一個值,但是如果發生失敗,其不會丟擲異常,而是返回一個預設值;put()
此類方法就是向物件中插入一個鍵值對。特別注意其插入NULL
和null
是不同的;
剛說到此類中的 NULL
,它與 JAVA 中的null
是不一樣的,它僅僅是JSONObject
中用於標識null
的物件。舉個例子:
1. put(name, null)
這個方法呼叫將會移除該物件中對應的鍵值;
2. put(name, JSONObject.NULL)
將會往物件中新增一個鍵值,而其值為 JSONObject.NULL
;
下面通過一個實際使用的程式碼來演示該類:
JSONObject jsonObject = new JSONObject("{\"first_name\":\"Taylor\",\"last_name\":\"swifter\"}");
String firstName = jsonObject.getString("first_name");
String lastName = jsonObject.getString("last_name");
Log.i("swifter", firstName + " " + lastName); //輸出 Taylor swifter
jsonObject.put("first_name", "Avril");
Log.i("swifter", jsonObject.toString()); //輸出 {"first_name":"Avril","last_name":"swifter"}
通過程式碼也可以看到JSONObject
的簡單用法,可以看到這個類也可以用來進行構建 JSON 字串,只要不斷向類中使用put()
方法插入或是修改,在最後使用toString()
就可以得到最終的 JSON 了。
關於這個toString()
這個函式後面還會提到,下面介紹的是在這四個類中第二重要的類:表示陣列的JSONArray
。
JSONArray
該類表示了 JSON 中的值的陣列,可以簡單的理解其為一個普通陣列,也有getXXX()
和optXXX()
方法,但是基本都需要傳入索引值。這個類代表了JSON 中的一個包裹在方括號的字串,值和值之間使用逗號隔開的資訊。
除此之外,這個類有很多性質都與JSONObject
一樣,比如說型別轉換,對於NULL
和null
的處理,有get
,put
,opt
方法等,所以,只要你熟悉了JSONObject
,那麼使用這個類,也會非常容易:
JSONArray jsonArray = new JSONArray("[10,11,12,13,14,15,16]");
for(int index = 0; index < jsonArray.length(); index++) {
Log.i("swifter", index+" : "+jsonArray.getInt(index));
}
此段程式碼的輸出是將10到16這幾個陣列中的數打印出來。在更多情況下,該類一般都是與JSONObject
一起使用的,因為普遍的 JSON 都是其中的某一個欄位是陣列,因此需要先使用JSONObject
進行解析,然後使用getJSONArray()
再來獲取這個陣列的資訊並進行處理:
JSONObject jsonObject = new JSONObject("{\"first_name\":\"Taylor\",\"last_name\":\"swifter\",
\"array\":[first, second, third, fourth]}");
JSONArray jsonArray = jsonObject.getJSONArray("array");
for(int index = 0; index < jsonArray.length(); index++) {
Log.i("swifter", index+" : "+jsonArray.getString(index));
}
此段待會會將 JSON 中array的四個值以字串的形式依次打印出來。
JSONStringer
此類可以用於快速構建 JSON 文字,它實現了JSONObject
中的兩個toString()
方法,對於大多數程式設計師來說,應該直接呼叫JSONObject
的toString()
方法而忽略這個類的:
JSONObject object = …
String json = object.toString();
它使用了一種類似於 XML 事件解析的方式來實現 JSON 構建,例如它有key()
方法用於插入鍵,有value()
方法用於插入值,而且還有array()
和endArray()
用於開始和結束插入陣列,有object()
和endObject()
方法用於開始和結束插入 JSON 內容。
僅僅說其有什麼方法比較澀會難懂,那就上程式碼:
JSONStringer jsonStringer = new JSONStringer();
jsonStringer.object().key("first_name").value("Taylor").key("last_name").value("swifter");
jsonStringer.key("array").array().value(12).value(13).value(14).endArray().endObject();
Log.i("swifter", jsonStringer.toString()); //輸出 {"first_name":"Taylor","last_name":"swifter","array":[12,13,14]}
可以看到對於 JSON 的構建,該類就是通過這幾個方法的呼叫來實現的。
剛才說到JSONObject
類的toString()
方法就是通過這個類來實現的,那它是怎麼實現的呢?現在就來看看程式碼吧。它有兩個方法,為了簡單起見,我們就看其中一個:
/**
* Encodes this object as a compact JSON string, such as:
* <pre>{"query":"Pizza","locations":[94043,90210]}</pre>
*/
@Override public String toString() {
try {
JSONStringer stringer = new JSONStringer();
writeTo(stringer);
return stringer.toString();
} catch (JSONException e) {
return null;
}
}
void writeTo(JSONStringer stringer) throws JSONException {
stringer.object();
for (Map.Entry<String, Object> entry : nameValuePairs.entrySet()) {
stringer.key(entry.getKey()).value(entry.getValue());
}
stringer.endObject();
}
這段程式碼顯示了JSONObject
是如何處理toString()
的,其主要的工作在writeTo()
這個函式中,而又可以看到,這個函式也是呼叫的JSONStringer
的key()
和value()
等方法來實現 JSON 構造的。另一個toString()
也類似,僅僅是是用了JSONStringer
的另一個建構函式而已。
JSONTokener
這個類是四個類中最不常用的一個類,它能夠將一個 JSON 字串(RFC 4627)解析到相關的物件,對於大多數客戶端僅僅需要使用它的建構函式和nextValue()
函式:
String json = "{"
+ " \"query\": \"Pizza\", "
+ " \"locations\": [ 94043, 90210 ] "
+ "}";
JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
String query = object.getString("query");
JSONArray locations = object.getJSONArray("locations");
可見,這個類就是和JSONObject
的建構函式一起使用的,用於解析 JSON 源字串,還例如:
JSONObject jsonobj = new JSONObject(new JSONTokener(new FileReader(new File("json.txt"))));
上面的四個類的內容都如此吧。相比於其他第三方庫,內建的JSON解析功能上確實非常簡單,但在很多場景下也是完全夠用的。當熟悉了這幾個類之後,我們也就可以權衡一下是否真的需要引用第三方庫才能完成需求了。如果能滿足的話,為什麼還需要引用其他庫呢。