配合分支:day04/start Repo

興沖沖的把 App 寫出來啦,強迫各位看我拍的照片!切換到對應的分支後,可以按下 Android Studio 右上角看起來像是播放鍵的東西,就可以把這個 App 編譯到模擬器上囉。

現在畫面看起來有幾張照片,上面有新增日記按鈕。看起來一切都很完美,差不多是該出事的時候了,新增日記按鈕,按下去居然沒有反應 ?點擊下去應該要有輸入新日記的畫面才對!
開始建立這系列文章的套路了嗎?出現了問題,接著一起來導讀看程式碼,請先不要叫 AI Agent 修正,我們先 trace 問題可能出現在哪。
請開啟 Android Studio,把專案打開。將分支切換到 day04/start。

Android Studio 也能切換分支。
所有的程式,一啟動就跑的區塊,稱之為進入點。Android App 的進入點是 MainActivity.kt (通常是這樣,不過可以自定義。一般來說去找 Main 開頭的試試)。

MainActivity 是照片日記的進入點,先看看做了什麼。裡頭有一個 onCreate() ,這類的區塊稱之為 Function (函式),如果曾經寫過 Java,他們習慣稱之為 Method (翻譯是「方法」)。
看名稱這個應該是 MainActivity 被創造 出來後,會跑的區塊。
setContent 由名字可知,設定內容。第一個應該跟外觀有關,因為名稱有 Theme。接下來,看到 PhotoDiaryApp() 這個看起來就超級可疑。
請把游標移到 PhotoDiaryApp() 按下 Cmd + B (Windows/Linux:Ctrl + B),跳到這個檔案。
這什麼?初學就要看 190 行 Code 太多了吧!冷靜一點,先來看 PhotoDiaryApp() 這個 Function。看到前面有 fun 了嗎?不是很開心啦,代表這一個區塊是 Function。看一下做了什麼。先看這一塊:

來說文解字,if (條件) 區塊如果條件成立,就會跑到那一個 code 區塊,反之跑去 else。這裡的條件是 isAddingDiary 往上看一下。
var isAddingDiary by remember { mutableStateOf(false) }
看到後面的 stateOf 裡面是 false,就是否啦。另外一個值是 true。這種「開關」,即是所謂的 boolean 值 (布林值) 只能有「是」或是「否」。這是一個變數的型別 (Type),前面的 var 則代表這是一個可以被改變的變數,(還有不可以被改變的,但先知道 var 就好)。除了 boolean 值,還有其他的變數型別,未來遇到再介紹。

將 Android Studio 的 Inlay Hints 全開啟 (除了 Code vision),IDE 會顯示這個變數是什麼型別。
所以被 if(isAddingDiary) 包起來的是「正在加入日記」,就是新增日記該去的地方。看看兩個區塊分別叫了哪些 Function。
也就是說,「正在加入日記」,就會顯示 DiaryForm (Form 是表格的意思,超可疑對吧)。沒有「正在加入日記」就會顯示 List 列表。
還看到幾個超可疑的地方,先來看看 DiaryForm 和 DiaryList,可以傳什麼進去,沒錯 Function 可以把資料丟進去。

DiaryForm 可以吃兩個變數,分別是兩個 Function (欸是的,Function 是一個「型別」,另外一個名稱是 lambda)。
往下拉一下,看看這兩個 Function 在哪裡被叫呢?

在 Button 的 onClick 推測是按下了按鈕之後,某一個 Function 會被叫起來。有儲存,以及取消。
還發現一件事 Function Type 可以把「變數」一起帶回去 像是儲存的 title 了 note,就是標題和筆記內容,可以跟著一起回去。(我們會把這類的「變數」稱之為 callback function)

往回看 DiaryForm 這兩個 Function 在 isAddingDiary 做了啥,發現 onSave 和 onCancel 個自寫了一個 Function 來對應上面被叫起來的行為。發現怪事,他們都有把:
isAddingDiary = false
Hmm... 🤔

List 則是除了 onAddClick 這個 Function,還傳了一個 DiaryEntry 的列表 List,從畫面來看合理,應該就是送了三張照片的資料進來,DiaryEntry 應該就是紀錄的資料 (可以自行 Cmd + B 去看定義)。重點放在 onAddClick 這個 Function 在哪個階段被叫的?

在「新增日記」的按鈕 (Button) 上,按下去的時候要叫的!看起來離問題很近了。回去 isAddingDiary 不成立時,這裡怎麼處理的:

ㄏ,好像找到原因囉,原來是 onAddClick 送了一個空包彈!(沒錯,Function 可以空包彈 {} 代表什麼都不會做)
DiaryList(
entries = entries,
onAddClick = {
isAddingDiary = true // <== Add this
}
)
也就是說,只要把 onAddClick Function 接通就行了,馬上來試試成果吧:

爽,成功新增了新的日記。雖然結果看起來好像哪裡怪怪的但反正今天的問題解決了。

MainActivity 開始。fun 標出的可執行區塊;Java 常叫 Method。PhotoDiaryApp() 就是在呼叫另一個 Function,Android Studio 可以用 Cmd + B (Windows/Linux 用 Ctrl + B) 來跳轉。if / else:條件成立跑一邊,不成立跑另一邊,本次的範例用來決定顯示表單還是列表。true / false 的開關型別;isAddingDiary 就是這種值。var:可以被改寫的變數;例如範例中:把 isAddingDiary 從 false 改成 true,畫面才會切換。onSave、onCancel、onAddClick 都是。onSave(title, note) 就是把標題和內容交回上層。{}:可以但什麼都不做;按鈕有呼叫 onAddClick,上層卻接空包彈,所以畫面不變。接上 isAddingDiary = true 才算把事件接通。