iT邦幫忙

2026 iThome 鐵人賽

DAY 21
1

配合分支:day21/start,Repo: 按我

心情可不可以改?現在新增日記,心情都是固定的,日記本身的「心情」也不能改,就趁這個機會來調整吧。
前一陣子介紹過 sealed class 用來做「狀態」的區分。也有另外一種比較輕量的方式能做,叫做 enum class。它很適合用來給 Entity 裡頭,任何可以「窮舉」的狀態。 enum class 很適合實作「心情」這個資料。

Enum Class

直接用案例來說明,新增 Mood.kt,內容填入:

enum class Mood(val displayName: String) {
    CALM("平靜"),
    FOCUSED("專注"),
    IMPRESSED("震撼")
}

這代表這個 enum 有三個狀態:CALMFOCUSEDIMPRESSED 三者,enum class 可以帶一個變數,這裡就用 displayName 這個字串來作為範例。

接著把 DiaryEntry.kt Entity 的 mood 字串,從 String 改成這個 enum class:

val mood: Mood  // 👈🏼 這個改成 Mood

先著就是牽一髮而動全身,畢竟改了很深沉的東西。不過不用擔心,先從資料層的寫入/讀取開始調整。

JSON 寫入/讀取

資料寫入以及讀取,只需要來看 LocalDiaryStorage 這個 class 即可。

寫入調整

專注於 override fun save() {} 這個 save 的 Function,切記 JSON 是「文字檔案」,這也是為何 Mood 還需要 displayName 這個 String。

// before
jsonObject.put("mood", entry.mood)

// after
jsonObject.put("mood", entry.mood.displayName)  // 👈🏼 改為 displayName

這樣一樣可以寫入字串。

讀取調整

專注於調整 override fun load() {} 這個 load 的 Function。這一段比較棘手的地方是需要將文字轉換回 Enum。文字有可能會遇到隨意亂寫的情況,故都需要加上處理「不知道這是什麼東西」的例外狀況,這時就 throw 錯誤出去外面就好。

https://ithelp.ithome.com.tw/upload/images/20260909/20141615Yyv3QHbYhm.png

UI 更新

心情從單純的字串,變成了 enum class。調整方式很單純,比如:
日記卡片的:

// before
Text(text = "心情:${entry.mood}")

// after,直接去拿 displayName 就好
Text(text = "心情:${entry.mood.displayName}")

ViewModel 在產生 Sample Data 時也用了一些,這邊調整就可以很容易看出 enum class 好用之處。打個比方像是建立新照片日記時塞給他的「平靜」預設值。

val newEntry = DiaryEntry(
	photo = draftPhoto,
	title = normalizedTitle,
	note = normalizedNote,
	mood = "平靜",
	createdAt = LocalDateTime.now()
)

現在 Mood 變成一個 enum,則直接改成 Mood.CALM 就好,其他的依樣畫葫蘆。


配合分支:day21/mood-model,Repo: 按我

接下來來加入一個下拉選單,可以自由選擇心情。

https://ithelp.ithome.com.tw/upload/images/20260909/20141615pX4YvgwdjB.png

JSON 寫資料的部分已經完成了,這一塊全部都是 View 這邊的工(畫面的),牽扯到「畫面狀態」所以也需要調整 ViewModel。先在 ViewModel 紀錄新增日記時「目前選的心情是哪個」。

https://ithelp.ithome.com.tw/upload/images/20260909/20141615qbbZcN3JWi.png

有了紀錄心情的 State 後,其他就簡單了,就跟 Title 和 Note 的做法一樣,製作新日記時寫入即可。

val newEntry = DiaryEntry(
	photo = draftPhoto,
	title = normalizedTitle,
	note = normalizedNote,
	mood = draftMood,   // 👈🏼 改成 draftMood 即可
	createdAt = LocalDateTime.now()
)

接下來更新 ComposeView 這一側。有鑒於今天是第 21 天了,大家應該已經有「資料流」的概念。不外乎就是將「狀態」傳入 ComposeView,而 ComposeView 透過 callback function 與內部其他元件溝通(不是畫面的)。

先加入這個下拉元件:

https://ithelp.ithome.com.tw/upload/images/20260909/20141615bsGIzONpcF.png

請在新建照片日記的 DiaryForm 加入 MoodDropdown 將相對應的資料流串上即可:

https://ithelp.ithome.com.tw/upload/images/20260909/20141615H3F9zbepEv.png

就將這個「調整心情的功能加上去啦」。

Bonus

如果想在清單中的日記卡片,也加上心情下拉選單,該怎麼做呢?(解答在 GitHub Repo 之中)

TL;DR

  • enum class:用 enum class 把可以「窮舉」的狀態列出來;心情只有少數幾種,很適合用它取代原本的字串。
  • 窮舉:enum 的狀態是有限且固定的(CALMFOCUSEDIMPRESSED),比任意字串更不容易打錯。
  • 帶變數的 enum(displayName):enum class 可以帶一個變數;這裡用 displayName 存「平靜/專注/震撼」等顯示文字,與 Enum 名稱分開。
  • 型別(type):把 Entity 的 moodString 改成 Mood;型別一改會「牽一髮而動全身」,需要逐步調整。
  • JSON 是文字檔案:寫入時要轉回字串 entry.mood.displayName,因為 JSON 只能存文字,不能直接存 Enum。
  • throw 例外:讀取時把文字轉回 Enum,遇到看不懂的值就 throw 丟出去,處理「不知道這是什麼東西」的情況。
  • State(畫面狀態):在 ViewModel 用 draftMood 記錄「目前選的心情」,跟 Title、Note 的做法一樣。
  • 預設值(Sample Data):建立新日記時把心情塞 Mood.CALM 當「平靜」預設值,取代原本的字串 "平靜"

上一篇
[Day20] 補充漏掉的資訊
下一篇
[Day22] 搜尋及過濾
系列文
我的第一個手作りAndroid App!快樂學習物件導向程式設計!22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
chiaominchang222
iT邦新手 4 級 ‧ 2026-09-09 22:33:12

壞心情~~~

0
AndyAWD
iT邦新手 1 級 ‧ 2026-09-09 23:33:02

改變心情,好耶

我要留言

立即登入留言