Android中轉換JSON的工具-GSON

廖時賢
Nov 14, 2020

--

JSON作為目前資料交換的主流格式之一,在很多程式語言中都有支援針對其格式做轉換的功能,而用來構築Android App的Java和Kotlin當然也在其中,所以這篇會介紹JSON以及如何在Android中使用Gson來做JSON物件的轉換。

何謂JSON

JSON,全名是JavaScript Object Notation,是一種輕量級的資料交換格式,而從名稱可以得知他是從JavaScript中衍生出來的,而其中包含的格式只有2種-物件(Object)和陣列(Array),下面講一下這兩者的差異。

物件(Object)

在JavaScript中,物件的表示法是用大括號{}將資料包起來,而其中的資料則是鍵-值對(key-value pair),每個鍵一定都是字串,而值可以是數值、字串、布林或者是null,鍵-值對之間用逗號","做區隔,範例如下

{
"name" : "John",
"age" : 18,
"handsome" : true,
"rich" : false,
"girlFriend" : null
}

在上面的範例中建立了一個JSON Object,名字叫John,年齡18歲,很帥但不富有,沒有女朋友(純屬範例,叫John的不要生氣😅);而JSON Object的特性是,其中的各個key-value pair是不需要按照順序給的,所以就算先定義年齡再定義名字,還是可以視作為同樣的JSON Object;而因為資料都是一個key對到一個value,因此可以透過呼叫這個物件裡面的Key(比如"name")得到在這個物件中對應的值("John")。

陣列(Array)

JavaScript中陣列的表示法是用中括號[]包起來,裡面的資料只有值,可以用的類型跟Object一樣,有數值、字串、布林或者null,每個值之間同樣用逗號做區隔,舉例如下

[
1,
"demo",
true,
null
]

在這個範例中建立了一個JSON Array,與JSON Object不同,JSON Array值的順序是不能變動的,因為每個值有對應到一個索引(index),所以如果呼叫這個陣列中的第0項,是可以得到1這個值的。

而物件和陣列是可以包含彼此的,比如

[  
{
"name":"Ram",
"email":"Ram12@testmail.com",
"sports":[
"basketball",
"soccer"
]
},
{
"name":"Bob",
"email":"bob32@testmail.com",
"sports":[
"baseball",
"swimming"
]
}
]

上面的範例中,在一個JSON Array中包含了兩個JSON Object,而每個Object有name、email、sports這3個鍵,其中sports的值是另一個JSON Array。

Android中的JSON轉換

開頭提到,在Android中有內建支援JSON的轉換,因此這邊先講一下怎麼透過內建的API來轉換JSON。

假設有一個data class用來儲存學生的數學和英文成績

如果有一個學生Tom,數學85分,英文90分,當要透過JSON格式將Tom的成績上傳時,可以透過org.json這個package來將data class轉換成JSON字串來上傳

這時如果把jsonStr打印出來,可以得到這樣一個字串

"{\"name\":\"Tom\",\"math\":85,\"english\":90}"

這時就可以將這筆資料上傳了;反過來說,如果透過網路得到了Mary這名學生資料的字串,要將他轉換成Student data class則是這樣做

先將JSON字串轉換成JSONObject,再透過每個key從JSONObject中撈資料出來,建立新的Student實體,最後可以得到一個Student實體

Student(name=Mary, math=95, english=76)

看起來這樣就完成了不是嗎?注意在上面的例子中,因為Student只有3樣資料,所以在得到JSON資料並轉換成Student時沒甚麼大問題,但試想如果今天data class裡面包了10幾樣數據呢?這時候透過key取得value的這個步驟就需要在解析JSON字串時重複10幾次,不但很耗時間、造成code不簡潔、甚至如果取得目標數值的類別錯誤時又需要去看到底是哪個值取錯,選擇正確的方法;為了解決這些問題,Gson就是一個不錯的工具。

使用Gson來做JSON轉換

首先將Gson Library加入APP層級的Dependencies

implementation 'com.google.code.gson:gson:2.8.6'

當要用到JSON轉換的時候,只要建立一個新的Gson實體,就可以透過這個實體來幫忙轉換

回到先前的例子,假設要在Student這個data class跟JSON格式之間做轉換,那上面這段程式碼就會變成

跟上面使用內建的json package相比,使用Gson是不是相對簡單很多呢。

@SerializedName

有時候從網路上得到的JSON資料和我們自訂的data class欄位名稱不一樣,如果直接轉換的話會出錯,這時候就可以透過SerializedName這個註解來幫忙,在Gson文件中對於這個註解是這樣解釋的

An annotation that indicates this member should be serialized to JSON with the provided name value as its field name.

也就是說,當有設置SerializedName註解,Gson在做轉換的時候會將特定參數的key轉換成設置的名稱,直接舉例來看,上面Student data class中有一個參數name,但網路上的資料不是叫name而是叫studentName,那就可以在Student data class中加上註解

當要把Student這個data class轉換成JSONObject時,本來叫做name的參數會轉換成studentName這個欄位,反過來說,當得到的JSONObject中有studentName這個欄位時,在轉換中會對應到Student中的name參數;而其他沒有特別註解的則是本來叫甚麼,轉換後還是叫甚麼。

結論

透過Gson,可以快速的幫助我們處理網路資料和本地data class的轉換,但Gson對於Kotlin其實沒有做到完全支援(Kotlin不是Google親兒子嗎🤔),比如在Kotlin最被常拿來做為賣點之一的空安全檢驗,Gson就沒有支援,也因此有其他的Library也被開發出來作為更適合Kotlin使用的替代方案,比如身為Gson開發者之一的Jesse Wilson開發出的Moshi,作者更在Reddit論壇上講了使用Kotlin開發時,為什麼要用Moshi取代Gson的原因(有興趣的朋友可以到這裡看看),因此隨著Kotlin越來越被廣泛使用,或許這篇文章也會變成時代的眼淚吧😅

參考資料

Google Developer Documentation -JSON
《Android》『JSON & GSON』- JSON 的基本程式語法教學
Gson User Guide(Github)

--

--

廖時賢
廖時賢

Written by 廖時賢

Android/React Native developer. Start coding by interesting and become a job now.

No responses yet