在Android架構實戰(三)—— Retrofit中,我們講到了Retrofit默認是用Gson作解析。但這並意味着我們就能夠一帆風順的使用了,因爲在實踐過程中,變通的地方很多,默認的解析方法往往會遇到許多困難,這裏還是決定單獨拿出來講一下。
其實GSON並不能算是一種框架級別的工具,不過它卻對快速開發能夠起到極大的促進作用。GSON是由谷歌開發的JSON快速解析類,官方文檔:Gson User Guide(需要翻牆),項目Github地址:google/gson。Gson採用了序列化的方式解析JSON串(因此,支持了Gson解析的類在序列化方面都會有很高的兼用性),在賦值的時候直接操縱內存,在速度上和簡潔性上,都會比android基本的解析方法好很多。因此,大部分的android開發人員和開源框架都使用了GSON。
一、基礎使用
<span style="font-size:14px;">Gson gson = new Gson(); // 可以構造單例進行處理
String jsonString = gson.toJson(myClass);
MyClass myClass = gson.fromJson(jsonString, MyClass.class);</span>
其中,需要對MyClass中的變量使用註解進行標註。Gson主要提供了以下幾種註解:- @Expose:被該註解標註的變量會被GSON處理(默認所有變量都會處理)。如果在一個類中,只存在個別變量需要被GSON解析,則可以使用Expose作單獨標註。相反的,如果只有個別變量不需要被GSON解析,則可以對需要忽略的變量使用transient關鍵詞(不是註解),而其他變量也不需要再額外添加Expose註解了。
- @SerializedName("keyName"):標識JsonObject中對應的Key值。默認情況下,Gson會將變量名當做Key值來處理。但是通常情況下,正式的android包會做混淆處理,導致變量名被改變,因此,必須對每一個變量都使用SerializedName做標註才能保證不會出錯。
<span style="font-size:14px;">Type collectionType = new TypeToken<List<MyClass>>(){}.getType();
List<MyClass> classList = gson.fromJson(json, collectionType);</span>
在Retrofit的中,默認GsonConverter已經集成了這個過程了,因此在使用Retrofit的時候可以不用有這個顧慮二、拓展問題解決方法
- 服務器返回不標準的JSON串,如"{"key":"{"chilekey":"childvalue}"}"。在這個例子中,key對應的value應當是一個JsonObject,但由於value外邊包裹了一個引號,Gson會識別爲String。這個時候如果嘗試將其直接轉化爲一個自定義Class,則會報錯。爲了解決這個問題,只能拿一個String去存儲值,在需要用到的時候通過getter對其進行一個轉化, 示例如下:
<span style="font-size:14px;">class MyClass { @SerializedName("key") String childString; transient ChildClass childClass; public ChildClass getChildClass() { if (childClass == null) // 只進行一次轉化,提高效率 childClass = (new Gson()).fromJson(childString, ChildClass.class); return childClass; } class ChildClass { @SerializedName("childkey") String value; } }</span>
- 返回類型不固定。爲了提高複用性,服務器在很多時候會在同一個接口返回不同類型的值,這就需要我們動態的去設置Gson的解析類。然而,由於Gson是通過靜態的註解方法進行設置的,因此沒有辦法對返回結果做動態判斷。想要實現這個效果,要麼就通過請求值去判斷返回類型,然後對每一個返回類型寫一個接口,要麼就得用一個共通的類去存儲中間變量。第一種方法,相對來說比較囉嗦,複用性較低。因此,比較推薦使用第二種方法。那麼,應當拿什麼變量來做這個中間值呢?答案是LinkedTreeMap。當Gson不知道應當按照什麼類去解析的時候,就會將所有的變量轉化一個LiknedTreeMap。LinkedTreeMap本質上是一個Map,通過這個Map,就可以動態的去獲取當中所包含的key和value了。