iT邦幫忙

2022 iThome 鐵人賽

DAY 6
0
Mobile Development

【Kotlin Notes And JetPack】Build an App系列 第 6

Day 6.【Classes and Objects】Data Classes

  • 分享至 

  • xImage
  •  

今天會開始規劃每個頁面狀態的資料結構,並先理解 data class 使用情境與定義,以下如有解釋不清或是描述錯誤的地方還請大家多多指教:

什麼?

主要的目的為裝載資料並傳遞,我們可以使用 data class 來建立 DTO (Data Transfer Object) 或是 VO (Value Object),一個是資料傳輸用的物件、一個是用來呈現在畫面的資料物件:

// 接收資料來的結構 DTO
data class Product(
	val name: String, 
	val description: Strinng, 
	val price: Int, 
	val amount: Int
) 

// 介面只需顯示部份資料 VO
data class ProductPreview(
	val name: String, 
	val description: Strinng
)

為了確保程式生成的一致性和有意義的行為,data class 必須符合以下條件:

  • 主構造函數至少要有一個參數
  • 主構造函數的所有參數必須標示 valvar
  • class 不能是 abstract, open, sealedinner
// 如果要不帶參數的方式生成物件,那就需要給予預設的參數值 
data class User(val name: String = "", val age: Int = 0)
...
val user = User()

主構造函數的參數在 compile 後會產生以下的 method:

  • hashCode() 產生物件的 hash code
  • toString() 將結構轉成 "User(name="", age=0)" 文字
  • componentN() 按宣告的順序對應參數屬性
  • copy() 複製物件

| Declared properties in the class body

如果參數宣告在 class 內部的就不會實作上述的方法,來看看範例吧!一個參數是在主構造函數做宣告,一個是在 body 內做宣告:

data class Person(val name: String) {
    var age: Int = 0
}

val person1 = Person("John")
val person2 = Person("John")
person1.age = 10
person2.age = 20
// person1 == person2: true
// person1 with age 10: Person(name=John)
// person2 with age 20: Person(name=John)

只有 name 會在 compile 實作那些方法,所以上面在做物件比對的時候只會比對 name,componentN() 也只會產出 component1()

| Copy

copy 可以讓你改變物件的某些參數值,不會更動到原本的狀態:

val jack = Person(name = "Jack", age = 1)
val olderJack = jack.copy(age = 2)

// Person(name=John, age=1)
// Person(name=John, age=2)

但是如果是集合類的資料就不會複製新的記憶體來使用,所以針對複製後的集合操作,都是對同一個記憶體位址的資料做更動,例如:

val jack = Person(name = "Jack", age = 1, hobby = mutableListOf("draw", "sing"))
val olderJack = jack.copy(age = 2)
olderJack.hobby.add("swim")

// Person(name=John, age=1, hobby=[draw, sing, swim])
// Person(name=John, age=2, hobby=[draw, sing, swim])

如何?

| 設定

接下來要用 data class 來建立跟 API 接資料的 DTO 跟在頁面顯示的資料結構,我選這個 API 原因是因為它可以調整 response 來的參數,可以選擇我需要的資料,而每個參數所代表的意思可以閱讀他提供的文件,缺點可能就是他搜尋 API 只能輸入英文:
https://ithelp.ithome.com.tw/upload/images/20220919/20151145MDWnwyo66t.png

| API 測試

網站提供一個測試 API 回應的功能,可以先用這個功能來模擬 API 接上之後會給的 Response 以及要給的 Request 資料格式( weatherapi.com / 註冊取得個人的 API key ),從 app 畫面呈現來看我會需要預報跟搜尋,所以試打了 forecast 跟 search 這兩隻得到下面的結果:

  • forecast
{
    "location": {
        "name": "London",
        "region": "City of London, Greater London",
        "country": "United Kingdom",
        "lat": 51.52,
        "lon": -0.11,
        "tz_id": "Europe/London",
        "localtime_epoch": 1660963985,
        "localtime": "2022-08-20 3:53"
    },
    "current": {
        "last_updated_epoch": 1660963500,
        "temp_c": 15.0,
        "is_day": 0,
        "condition": {
            "text": "Clear",
            "icon": "//cdn.weatherapi.com/weather/64x64/night/113.png"
        },
        "wind_kph": 11.2,
        "humidity": 77,
        "feelslike_c": 14.6,
        "uv": 1.0
    },
    "forecast": {
        "forecastday": [
	            {
                "date": "2022-08-20",
                "date_epoch": 1660953600,
                "day": {
                    "maxtemp_c": 23.5,
                    "mintemp_c": 14.9,
                    "avgtemp_c": 19.1,
                    "maxwind_kph": 17.3,
                    "avgvis_km": 10.0,
                    "avghumidity": 59.0,
                    "daily_chance_of_rain": 0,
                    "condition": {
                        "text": "Overcast",
                        "icon": "//cdn.weatherapi.com/weather/64x64/day/122.png" 
                    },
                    "uv": 4.0
                },
                "astro": {},
                "hour": [
                    {
                        "time_epoch": 1660950000,
                        "time": "2022-08-20 00:00",
                        "temp_c": 17.1,
                        "is_day": 0,
                        "condition": {
                            "text": "Clear",
                            "icon": "//cdn.weatherapi.com/weather/64x64/night/113.png"
                        },
                        "wind_kph": 12.2,
                        "humidity": 60,
                        "feelslike_c": 17.1,
                        "chance_of_rain": 0,
                        "uv": 1.0
                    },
					...
				]
			}
        ]
    }
}
  • search
[
	{
        "id": 2478871,
        "name": "Taipei",
        "region": "T'ai-pei",
        "country": "Taiwan",
        "lat": 25.04,
        "lon": 121.53,
        "url": "taipei-tai-pei-taiwan"
    },
	...
]

| DTO

以 search API 為範例:

data class SearchResponse(
    val result: List<Search>
)
data class Search(
    val id: Long,
    val name: String,
    val region: String,
    val country: String,
    val lat: Float,
    val lon: Float,
    val url: String
)

| VO

根據我們的 UI 決定要呈現什麼資料在上面,以主頁為範例:

sealed class HomeVo(val id: Int)
// display
data class CityCard(
    val cityId: Int,
    val cityName: String,
    val day: String,
    val temp: String,
    val wind: String,
    val wet: String,
    val rain: String,
	val isMarked: Boolean
) : HomeVo(cityId)

data class CityDayTemp(
    val day: String,
    val maxTemp: String,
    val minTemp: String
)

data class CityHourTemp(
    val cityId: Int,
    val time: String,
    val temp: String
) : HomeVo(cityId)

// empty
data class EmptyState(val cityId: Int) : HomeVo(cityId)

Reference

Official Kotlin
Kotlin Journey


上一篇
Day 5.【Classes and Objects】Sealed Classes
下一篇
Day 7.【Classes and Objects】Enum Classes
系列文
【Kotlin Notes And JetPack】Build an App30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言