Android解析JSON,你真的需要三方庫(kù)?

一般情況下,如果服務(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ù)。

json_icon.png

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、IntegersLongs、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ì)。特別注意其插入NULLnull是不同的;

剛說到此類中的 NULL,它與 JAVA 中的null是不一樣的,它僅僅是JSONObject中用于標(biāo)識(shí)null的對(duì)象。舉個(gè)例子:

  1. put(name, null) 這個(gè)方法調(diào)用將會(huì)移除該對(duì)象中對(duì)應(yīng)的鍵值;
  2. 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ì)于NULLnull的處理,有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)用JSONObjecttoString()方法而忽略這個(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)用的JSONStringerkey()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ù)呢。

2b013df0-5b70-4c07-833e-6d95101e2d10.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容