Android架構實戰(四)—— Gson

Android架構實戰(三)—— Retrofit中,我們講到了Retrofit默認是用Gson作解析。但這並意味着我們就能夠一帆風順的使用了,因爲在實踐過程中,變通的地方很多,默認的解析方法往往會遇到許多困難,這裏還是決定單獨拿出來講一下。

其實GSON並不能算是一種框架級別的工具,不過它卻對快速開發能夠起到極大的促進作用。GSON是由谷歌開發的JSON快速解析類,官方文檔:Gson User Guide(需要翻牆),項目Github地址:google/gson。Gson採用了序列化的方式解析JSON串(因此,支持了Gson解析的類在序列化方面都會有很高的兼用性),在賦值的時候直接操縱內存,在速度上和簡潔性上,都會比android基本的解析方法好很多。因此,大部分的android開發人員和開源框架都使用了GSON。

一、基礎使用

在導入Gson的jar包後,就可以按如下命令開始使用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做標註才能保證不會出錯。
在GSON中,JsonObject對應爲一個Class,JsonArray對應爲一個List,因此,在遇到嵌套的情況下,按照這個關係進行對應的處理即可。
值得一提的是,GSON對集合類型(List,  Set)的處理存在一定的限制,即在反序列化的過程中,沒有辦法去識別集合中的泛型類到底是什麼,因此,在反序列化的時候,需要用戶手動指定類型:
<span style="font-size:14px;">Type collectionType = new TypeToken<List<MyClass>>(){}.getType();
List<MyClass> classList = gson.fromJson(json, collectionType);</span>
在Retrofit的中,默認GsonConverter已經集成了這個過程了,因此在使用Retrofit的時候可以不用有這個顧慮

二、拓展問題解決方法

正如我一直提到的,高度封裝的簡潔性必然會帶來一定的拓展性問題,許多時候,默認的Gson解析方法可能無法支持開發人員的一些需求。我主要遇到過的一些情況有
  1. 服務器返回不標準的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>

  2. 返回類型不固定。爲了提高複用性,服務器在很多時候會在同一個接口返回不同類型的值,這就需要我們動態的去設置Gson的解析類。然而,由於Gson是通過靜態的註解方法進行設置的,因此沒有辦法對返回結果做動態判斷。想要實現這個效果,要麼就通過請求值去判斷返回類型,然後對每一個返回類型寫一個接口,要麼就得用一個共通的類去存儲中間變量。第一種方法,相對來說比較囉嗦,複用性較低。因此,比較推薦使用第二種方法。那麼,應當拿什麼變量來做這個中間值呢?答案是LinkedTreeMap。當Gson不知道應當按照什麼類去解析的時候,就會將所有的變量轉化一個LiknedTreeMap。LinkedTreeMap本質上是一個Map,通過這個Map,就可以動態的去獲取當中所包含的key和value了。
可以看到,LinkedTreeMap是Gson中一個解決拓展性的問題關鍵類,當遇到任何不兼容或者非靜態的問題時,都可以臨時摒棄GSON的封裝方法,自己來進行有針對性的解析,這個開發思路顯得相當的優雅。當然,LinkedTreeMap會將所有的變量都進行讀出和轉換,效率上或許會受到一定的影響,因此不適宜過多使用。

三、小結

解決了拓展性的問題後,對於Gson的使用就基本一帆風順了。在使用的時候具體問題具體分析即可。

RxJava、Retrofit和Gson這三個庫的結合,在構造代碼框架的時候起到了決定性的作用,這三個庫之間相輔相成,相互配合,從各個方面都對代碼的整體質量有一個提升(解耦、複用、簡潔、高性能)。因此,十分推薦各位開發人員的時候可以已這個三個庫爲基礎進行架構的搭建。

發佈了33 篇原創文章 · 獲贊 43 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章