1. 程式人生 > >Android解析JSON,你真的需要三方庫?

Android解析JSON,你真的需要三方庫?

一般情況下,如果伺服器返回 JSON 資料,而且你又是做 Android 的,那麼你首先想到的可能是GSON,或是fastJson這樣的框架。這些框架能夠很方便和快速的讓我們將 JSON 轉換成本地物件,是開發的首選。但是引用三方庫也是有代價的,顯而易見的就是包體積增大,庫的升級等。這個時候,就需要想一想我們是不是必須要使用三方庫了。

其實在 Android 上處理 JSON ,Google 已經給我們提供了一些類,而這些類滿足了大多數簡單的需求。如果我們只是需要對 JSON 進行簡單的解析處理,那麼完全可以避免引入第三方庫。

json_icon.png

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的字串。而值則可以為 JSONObjectJSONArrayStringsBooleansIntegersLongsDouble 或者 JSONObject.NULL。特別注意,這裡的NULL可不是null,而是JSONObject的一個內部類。

對於這個類,在使用時要要注意的就是在呼叫時,其會按照呼叫的方法進行型別轉換。下面就介紹一下三類函式:

  • getXXX() 獲取一個值,此方法如果發生失敗,例如沒有找到對應的鍵值或型別轉換失敗,就會丟擲一個JSONException異常;
  • optXXX() 此類方法也是用於獲取一個值,但是如果發生失敗,其不會丟擲異常,而是返回一個預設值;
  • put()此類方法就是向物件中插入一個鍵值對。特別注意其插入NULLnull是不同的;

剛說到此類中的 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 一樣,比如說型別轉換,對於NULLnull的處理,有getputopt方法等,所以,只要你熟悉了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()方法,對於大多數程式設計師來說,應該直接呼叫JSONObjecttoString()方法而忽略這個類的:

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()這個函式中,而又可以看到,這個函式也是呼叫的JSONStringerkey()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解析功能上確實非常簡單,但在很多場景下也是完全夠用的。當熟悉了這幾個類之後,我們也就可以權衡一下是否真的需要引用第三方庫才能完成需求了。如果能滿足的話,為什麼還需要引用其他庫呢。

2b013df0-5b70-4c07-833e-6d95101e2d10.jpg