一般情況下,如果服務(wù)器返回 JSON 數(shù)據(jù),而且你又是做 Android 的,那么你首先想到的可能是GSON,或是fastJson這樣的框架。這些框架能夠很方便和快速的讓我們將 JSON 轉(zhuǎn)換成本地對(duì)象,是開發(fā)的首選。但是引用三方庫(kù)也是有代價(jià)的,顯而易見的就是包體積增大,庫(kù)的升級(jí)等。這個(gè)時(shí)候,就需要想一想我們是不是必須要使用三方庫(kù)了。
其實(shí)在 Android 上處理 JSON ,Google 已經(jīng)給我們提供了一些類,而這些類滿足了大多數(shù)簡(jiǎn)單的需求。如果我們只是需要對(duì) JSON 進(jìn)行簡(jiǎn)單的解析處理,那么完全可以避免引入第三方庫(kù)。

org.json
在Android的參考文檔中,我們能發(fā)現(xiàn)一個(gè)包,名為:org.json。這個(gè)包下主要有四個(gè)類:
| 類名 | 描述 |
|---|---|
| JSONArray | A dense indexed sequence of values. |
| JSONObject | A modifiable set of name/value mappings. |
| JSONStringer | Implements toString() and toString() |
| JSONTokener | Parses a JSON (RFC 4627) encoded string into the corresponding object. |
關(guān)于 org.json 的代碼,還可以在 https://github.com/stleary/JSON-java 上找到,而且里面的類遠(yuǎn)不止這4個(gè),里面很多內(nèi)容都值得去探索一下。但是由于本文僅專注于在 Android 上利用此工具處理 JSON,所以就僅僅討論著四個(gè)類,下面將分別對(duì)著四個(gè)類逐一講解。
JSONObject
這個(gè)類是這四個(gè)類中最關(guān)鍵的一個(gè),它表示了一個(gè)可更改且無序的鍵值對(duì)集合,更簡(jiǎn)單一點(diǎn),可以直接認(rèn)為這個(gè)類表示了一個(gè) JSON 的信息。在 JSON 字符串中,其表示了一個(gè)包裹在花括號(hào)的字符串,鍵和值之間使用冒號(hào)隔開,鍵值和鍵值之間使用逗號(hào)隔開的。
在這個(gè)類中,其鍵名是唯一且不為null的字符串。而值則可以為 JSONObject、JSONArray、Strings、Booleans、Integers、Longs、Double 或者 JSONObject.NULL。特別注意,這里的NULL可不是null,而是JSONObject的一個(gè)內(nèi)部類。
對(duì)于這個(gè)類,在使用時(shí)要要注意的就是在調(diào)用時(shí),其會(huì)按照調(diào)用的方法進(jìn)行類型轉(zhuǎn)換。下面就介紹一下三類函數(shù):
-
getXXX()獲取一個(gè)值,此方法如果發(fā)生失敗,例如沒有找到對(duì)應(yīng)的鍵值或類型轉(zhuǎn)換失敗,就會(huì)拋出一個(gè)JSONException異常; -
optXXX()此類方法也是用于獲取一個(gè)值,但是如果發(fā)生失敗,其不會(huì)拋出異常,而是返回一個(gè)默認(rèn)值; -
put()此類方法就是向?qū)ο笾胁迦胍粋€(gè)鍵值對(duì)。特別注意其插入NULL和null是不同的;
剛說到此類中的 NULL,它與 JAVA 中的null是不一樣的,它僅僅是JSONObject中用于標(biāo)識(shí)null的對(duì)象。舉個(gè)例子:
-
put(name, null)這個(gè)方法調(diào)用將會(huì)移除該對(duì)象中對(duì)應(yīng)的鍵值; -
put(name, JSONObject.NULL)將會(huì)往對(duì)象中添加一個(gè)鍵值,而其值為JSONObject.NULL;
下面通過一個(gè)實(shí)際使用的代碼來演示該類:
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的簡(jiǎn)單用法,可以看到這個(gè)類也可以用來進(jìn)行構(gòu)建 JSON 字符串,只要不斷向類中使用put()方法插入或是修改,在最后使用toString()就可以得到最終的 JSON 了。
關(guān)于這個(gè)toString()這個(gè)函數(shù)后面還會(huì)提到,下面介紹的是在這四個(gè)類中第二重要的類:表示數(shù)組的JSONArray。
JSONArray
該類表示了 JSON 中的值的數(shù)組,可以簡(jiǎn)單的理解其為一個(gè)普通數(shù)組,也有getXXX()和optXXX()方法,但是基本都需要傳入索引值。這個(gè)類代表了JSON 中的一個(gè)包裹在方括號(hào)的字符串,值和值之間使用逗號(hào)隔開的信息。
除此之外,這個(gè)類有很多性質(zhì)都與JSONObject 一樣,比如說類型轉(zhuǎn)換,對(duì)于NULL和null的處理,有get,put,opt方法等,所以,只要你熟悉了JSONObject,那么使用這個(gè)類,也會(huì)非常容易:
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這幾個(gè)數(shù)組中的數(shù)打印出來。在更多情況下,該類一般都是與JSONObject一起使用的,因?yàn)槠毡榈?JSON 都是其中的某一個(gè)字段是數(shù)組,因此需要先使用JSONObject進(jìn)行解析,然后使用getJSONArray()再來獲取這個(gè)數(shù)組的信息并進(jìn)行處理:
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));
}
此段待會(huì)會(huì)將 JSON 中array的四個(gè)值以字符串的形式依次打印出來。
JSONStringer
此類可以用于快速構(gòu)建 JSON 文本,它實(shí)現(xiàn)了JSONObject中的兩個(gè)toString()方法,對(duì)于大多數(shù)程序員來說,應(yīng)該直接調(diào)用JSONObject的toString()方法而忽略這個(gè)類的:
JSONObject object = ...
String json = object.toString();
它使用了一種類似于 XML 事件解析的方式來實(shí)現(xiàn) JSON 構(gòu)建,例如它有key()方法用于插入鍵,有value()方法用于插入值,而且還有array()和endArray()用于開始和結(jié)束插入數(shù)組,有object()和endObject()方法用于開始和結(jié)束插入 JSON 內(nèi)容。
僅僅說其有什么方法比較澀會(huì)難懂,那就上代碼:
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]}
可以看到對(duì)于 JSON 的構(gòu)建,該類就是通過這幾個(gè)方法的調(diào)用來實(shí)現(xiàn)的。
剛才說到JSONObject類的toString()方法就是通過這個(gè)類來實(shí)現(xiàn)的,那它是怎么實(shí)現(xiàn)的呢?現(xiàn)在就來看看代碼吧。它有兩個(gè)方法,為了簡(jiǎn)單起見,我們就看其中一個(gè):
/**
* 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()這個(gè)函數(shù)中,而又可以看到,這個(gè)函數(shù)也是調(diào)用的JSONStringer的key()和value()等方法來實(shí)現(xiàn) JSON 構(gòu)造的。另一個(gè)toString()也類似,僅僅是是用了JSONStringer的另一個(gè)構(gòu)造函數(shù)而已。
JSONTokener
這個(gè)類是四個(gè)類中最不常用的一個(gè)類,它能夠?qū)⒁粋€(gè) JSON 字符串(RFC 4627)解析到相關(guān)的對(duì)象,對(duì)于大多數(shù)客戶端僅僅需要使用它的構(gòu)造函數(shù)和nextValue()函數(shù):
String json = "{"
+ " \"query\": \"Pizza\", "
+ " \"locations\": [ 94043, 90210 ] "
+ "}";
JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
String query = object.getString("query");
JSONArray locations = object.getJSONArray("locations");
可見,這個(gè)類就是和JSONObject的構(gòu)造函數(shù)一起使用的,用于解析 JSON 源字符串,還例如:
JSONObject jsonobj = new JSONObject(new JSONTokener(new FileReader(new File("json.txt"))));
上面的四個(gè)類的內(nèi)容都如此吧。相比于其他第三方庫(kù),內(nèi)置的JSON解析功能上確實(shí)非常簡(jiǎn)單,但在很多場(chǎng)景下也是完全夠用的。當(dāng)熟悉了這幾個(gè)類之后,我們也就可以權(quán)衡一下是否真的需要引用第三方庫(kù)才能完成需求了。如果能滿足的話,為什么還需要引用其他庫(kù)呢。
