iT邦幫忙

2021 iThome 鐵人賽

DAY 10
0

本篇文章同步發表在 HKT 線上教室 部落格,線上影音教學課程已上架至 UdemyYoutube 頻道。另外,想追蹤更多相關技術資訊,歡迎到 臉書粉絲專頁 按讚追蹤喔~

程式碼範例

範例名稱:Gson 資料解析並印出藥局名稱
開發人員:HKT (侯光燦)
程式語言:Kotlin
開發環境:Android Studio 4.1.1 & Android 11 & Kotlin 1.4.21
授權範圍:使用時必須註明出處且不得為商業目的之使用
範例下載點:點我下載

JSON 資料在解析時,較為耗手機效能、處理也較慢,所以在解析資料時,業界普遍會透過 Gson 來解析 JSON 資料格式。Gson 是 Google 開發的開源 Library。這一節課程,我們將來介紹,如何使用 Gson 來解析資料。

添加 Gson 依賴庫 (dependencies)

在 GRADLE (Module) 層級 dependencies 內加入:

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

資料轉換

JSON 資料轉換成 Gson 是透過 Gson 提供的 fromJson(String json, Class classOfT) 這個方法。其中,fromJson 第一個欄位,要帶入的即是我們透過 Okhttp 獲取到的資料,第二個欄位,需帶入我們自己定義的類別。

//pharmaciesData 為 Okhttp 獲取到的資料
val pharmaciesData = response.body?.string()

//PharmacyInfo 是我們自定義類別
val pharmacyInfo = Gson().fromJson(pharmaciesData, PharmacyInfo::class.java)

PharmacyInfo

JSON 資料轉換成 Gson,仍須注意的是資料層次概念以 口罩資料 為例,若我們要取得最外層資料,如:「 “type”: “FeatureCollection”」,我們可以寫成這樣:

class PharmacyInfo(
    @SerializedName("type")
    val type: String
)

SerializedName 裡面要填的是,真實資料中的名稱,我們要獲取 type 所以填 type,所以寫成「@SerializedName("type")」以此類推。而如果你不喜歡,原本資料定義的名稱,你可以自定義常數值名稱,例如,想改成 my_type,就可以寫成這樣:

class PharmacyInfo(
    @SerializedName("type")
    val my_type: String
)

而如果我們想要印出資料,可以寫成這樣:

Log.d("HKT", "my_type: ${pharmacyInfo.my_type}")

輸出結果

my_type: FeatureCollection

而在原本 JSON 資料解析裡,如果我們沒有多加 has 或 isNull 來判斷欄位資料是否存在,會直接噴出例外錯誤。但是如果是 GSON,並不用多加判斷,只是因為沒有此筆欄位資料會回傳 null。例如,我們資料並沒有 typeeeeee 但我們寫成這樣:

class PharmacyInfo(
    @SerializedName("typeeeeee")
    val my_type: String
)

輸出結果

my_type: null

陣列與物件屬性的資料轉換

如果我們要獲取每間藥局名稱,剛開始學的的同學最容易犯的錯誤,會寫成這樣:

//錯誤範例
class PharmacyInfo(
    @SerializedName("name")
    val name: String
)

這樣的結果,GSON 並不會噴出例外錯誤,只是會得到 null 。這個問題出在資料層次問題,必須清楚的跟電腦說你要獲取哪一層資料,上方的寫法,電腦會誤以為你要獲取取第一層,但實際你是要獲取 features 「陣列」裡面的 properties 「物件」裡面的 name 值。所以應該改成:

class PharmacyInfo(
    @SerializedName("features")
    val features: List<Feature>
)

class Feature(
    @SerializedName("properties")
    val property: Property
)

class Property(
    @SerializedName("name")
    val name: String
)

層次中最需要注意的是,大括號 object {} 與中括號 array [],層次概念。瞭解之後,我們就可以透過 for 迴圈,取出每一間藥局名稱。

val pharmaciesData = response.body?.string()
val pharmacyInfo = Gson().fromJson(pharmaciesData, PharmacyInfo::class.java)

for (i in pharmacyInfo.features) {
    Log.d("HKT", "name: ${i.property.name}")
}

輸出結果

name: 中美藥局
name: 新東洋藥局
name: 辰好藥局
name: 杏安藥局
name: 明皇藥局
name: 全國大藥局
name: 政德藥局
name: 嘉方藥局
name: 慶豐綜合藥局
...
...
...

KT 的偷呷步

安裝外掛套件:「JSON To Kotlin Class」,快速將 JSON 資料轉換成 Class。

完整口罩資料類別定義

透過外掛套件的方式,快速幫我們產生對應的資料類別結構,並將原本分散的檔案,刻意全部集中到「PharmacyInfo.kt」檔案中,若採用外掛套件產生個別分開檔案也可,看公司文化或個人喜好。

package com.thishkt.pharmacydemo.data

data class PharmacyInfo(
    val features: List<Feature>,
    val type: String
)

data class Feature(
    val geometry: Geometry,
    val properties: Properties,
    val type: String
)

data class Geometry(
    val coordinates: List<Double>,
    val type: String
)

data class Properties(
    val address: String,
    val available: String,
    val county: String,
    val cunli: String,
    val custom_note: String,
    val id: String,
    val mask_adult: Int,
    val mask_child: Int,
    val name: String,
    val note: String,
    val phone: String,
    val service_periods: String,
    val town: String,
    val updated: String,
    val website: String
)

參考資料

HKT 線上教室
https://tw-hkt.blogspot.com/

Freepik
https://www.freepik.com/

Gson User Guide
https://github.com/google/gson


那今天【iThome 鐵人賽】就介紹到這邊囉~

順帶一提,KT 線上教室,臉書粉絲團,會不定期發佈相關資訊,不想錯過最新資訊,不要忘記來按讚,追蹤喔!也歡迎大家將這篇文章分享給更多人喔。

我們明天再見囉!!!掰掰~


上一篇
Day 9:JSON 資料解析
下一篇
Day 11:ProgressBar 忙碌圈圈
系列文
Android 口罩地圖入門實戰 30 天 (使用 Kotlin 程式語言)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言