一般情況下均牢,如果服務器返回 JSON 數(shù)據(jù),而且你又是做 Android 的才睹,那么你首先想到的可能是GSON
徘跪,或是fastJson
這樣的框架。這些框架能夠很方便和快速的讓我們將 JSON 轉換成本地對象琅攘,是開發(fā)的首選垮庐。但是引用三方庫也是有代價的,顯而易見的就是包體積增大坞琴,庫的升級等哨查。這個時候,就需要想一想我們是不是必須要使用三方庫了剧辐。
其實在 Android 上處理 JSON 解恰,Google 已經給我們提供了一些類锋八,而這些類滿足了大多數(shù)簡單的需求。如果我們只是需要對 JSON 進行簡單的解析處理护盈,那么完全可以避免引入第三方庫挟纱。
org.json
在Android的參考文檔中,我們能發(fā)現(xiàn)一個包腐宋,名為:org.json
紊服。這個包下主要有四個類:
類名 | 描述 |
---|---|
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. |
關于 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
的一個內部類擎值。
對于這個類,在使用時要要注意的就是在調用時逐抑,其會按照調用的方法進行類型轉換鸠儿。下面就介紹一下三類函數(shù):
-
getXXX()
獲取一個值,此方法如果發(fā)生失敗,例如沒有找到對應的鍵值或類型轉換失敗进每,就會拋出一個JSONException
異常汹粤; -
optXXX()
此類方法也是用于獲取一個值,但是如果發(fā)生失敗田晚,其不會拋出異常嘱兼,而是返回一個默認值; -
put()
此類方法就是向對象中插入一個鍵值對贤徒。特別注意其插入NULL
和null
是不同的芹壕;
剛說到此類中的 NULL
,它與 JAVA 中的null
是不一樣的接奈,它僅僅是JSONObject
中用于標識null
的對象踢涌。舉個例子:
-
put(name, null)
這個方法調用將會移除該對象中對應的鍵值; -
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()
這個函數(shù)后面還會提到疫剃,下面介紹的是在這四個類中第二重要的類:表示數(shù)組的JSONArray
钉疫。
JSONArray
該類表示了 JSON 中的值的數(shù)組硼讽,可以簡單的理解其為一個普通數(shù)組巢价,也有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這幾個數(shù)組中的數(shù)打印出來捏膨。在更多情況下,該類一般都是與JSONObject
一起使用的,因為普遍的 JSON 都是其中的某一個字段是數(shù)組号涯,因此需要先使用JSONObject
進行解析目胡,然后使用getJSONArray()
再來獲取這個數(shù)組的信息并進行處理:
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 文本链快,它實現(xiàn)了JSONObject
中的兩個toString()
方法誉己,對于大多數(shù)程序員來說,應該直接調用JSONObject
的toString()
方法而忽略這個類的:
JSONObject object = ...
String json = object.toString();
它使用了一種類似于 XML 事件解析的方式來實現(xiàn) JSON 構建域蜗,例如它有key()
方法用于插入鍵巫延,有value()
方法用于插入值,而且還有array()
和endArray()
用于開始和結束插入數(shù)組地消,有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 的構建脉执,該類就是通過這幾個方法的調用來實現(xiàn)的疼阔。
剛才說到JSONObject
類的toString()
方法就是通過這個類來實現(xiàn)的,那它是怎么實現(xiàn)的呢半夷?現(xiàn)在就來看看代碼吧婆廊。它有兩個方法,為了簡單起見巫橄,我們就看其中一個:
/**
* 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()
這個函數(shù)中,而又可以看到湘换,這個函數(shù)也是調用的JSONStringer
的key()
和value()
等方法來實現(xiàn) JSON 構造的宾舅。另一個toString()
也類似,僅僅是是用了JSONStringer
的另一個構造函數(shù)而已彩倚。
JSONTokener
這個類是四個類中最不常用的一個類筹我,它能夠將一個 JSON 字符串(RFC 4627)解析到相關的對象,對于大多數(shù)客戶端僅僅需要使用它的構造函數(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");
可見帆离,這個類就是和JSONObject
的構造函數(shù)一起使用的蔬蕊,用于解析 JSON 源字符串,還例如:
JSONObject jsonobj = new JSONObject(new JSONTokener(new FileReader(new File("json.txt"))));
上面的四個類的內容都如此吧哥谷。相比于其他第三方庫岸夯,內置的JSON解析功能上確實非常簡單,但在很多場景下也是完全夠用的们妥。當熟悉了這幾個類之后猜扮,我們也就可以權衡一下是否真的需要引用第三方庫才能完成需求了。如果能滿足的話王悍,為什么還需要引用其他庫呢破镰。