使用單元 1 中學到的技能,建構簡單的 Lemonade 應用程式。
學習目標
- 在 Google 上搜尋您在應用程式中不認得的字詞、錯誤訊息和程式碼片段。
- 測試程式碼、解讀錯誤,然後變更程式碼並重複測試。
- 回去閱讀先前在 Android 基本概念單元 1 中的內容,溫故知新。
- 將您知道可順利執行的程式碼 (例如專案內提供的程式碼,或是您先前在單元 1 中學到的其他應用程式的解決方案程式碼) 與您編寫的程式碼進行比對。
應用程式總覽
我們將建立簡單的互動式行動應用程式,讓您可以使用該應用程式榨取一杯檸檬汁。
成品 Lemonade 應用程式將由單一畫面組成。使用者初次啟動應用程式時,系統會提示使用者輕觸檸檬樹的圖片,藉此挑選檸檬。

使用者在輕觸檸檬樹後便會看到一顆檸檬,可以輕觸以「擠壓」檸檬數次 (次數不固定,系統將隨機產生所需的擠壓次數),才會移動到下一個畫面。

使用者輕觸擠壓至正確次數後,便會看到玻璃杯圖片,可以「喝下」檸檬水。

按一下飲用檸檬汁之後,玻璃杯就會變成空的,使用者只要再次輕觸圖片,就能返回第一個畫面,再從檸檬樹中選取其他檸檬。

這款應用程式的設計簡單,且提供單一活動。應用程式的不同狀態 (使用者選取檸檬、擠壓檸檬、喝檸檬汁、以及最後的空杯) 都會以「狀態機器」呈現。
雖然這聽起來像是空泛的理論術語,但這僅表示應用程式的狀態 (也就是要向使用者顯示哪些文字和圖片) 是取決於包含應用程式狀態的變數 (select 和 squeeze等等)。系統會一併更新應用程式的狀態會連同任何其他必要的變數,並在完成所有更新後分別設定使用者介面 (設定圖片和文字)。
系統已為您定義應用程式狀態的所有變數。您的工作是建構應用程式的版面配置並實作邏輯,讓使用者介面按預期在每個狀態之間轉換。
測試程式碼
對於 Lemonade 應用程式 (以及日後的專案),系統會提供一些自動化測試,讓您驗證程式碼是否可如預期般運作。Lemonade 應用程式的範例專案包含幾項測試,您可以執行測試,以確認是否已正確實作邏輯。
下載專案程式碼
資料夾名稱是 android-basics-kotlin-lemonade-app
。在 Android Studio 中開啟專案時,請選取這個資料夾。
然後在 Android Studio 中開啟剛才下載完成的專案
建立使用者介面
Lemonade 應用程式只需要基本的版面配置;您只需要兩個檢視畫面,就能實作所有功能。
- 為使用者提供操作說明的
TextView
。 - 根據應用程式目前狀態 (例如要擠壓的檸檬) 顯示圖形的
ImageView
。
您的目標是運用您掌握的版面配置編輯器知識,建構如下版面配置:兩個檢視畫面都在畫面中央,且 TextView
位於 ImageView
上方。

實際完成畫面:
讓應用程式與使用者互動
版面配置完成之後,請開啟 MainActivity.kt
。您可以在這裡實作所有應用程式的邏輯。您會發現已經有一些程式碼。且有許多標示為 // TODO:
的註解 (如以下範例所示)。這些都是您要完成的工作。

您必須實作下列三項基本工作,才能讓檸檬汁應用程式正常運作。
- 設定
lemonImage
ImageView
以回應使用者輸入的內容。 - 實作
clickLemonImage()
以更新應用程式的狀態。 - 實作
setViewElements()
,以根據應用程式目前的狀態更新使用者介面。
步驟 1:設定 ImageView
輕觸圖片檢視畫面後,應用程式就會從一個狀態切換成其他狀態。在 onCreate()
結尾,需要設定兩個事件監聽器。
setOnClickListener()
應更新應用程式的狀態。方法是clickLemonImage()
。setOnLongClickListener()
會回應使用者長按圖片的事件 (例如,使用者輕觸圖片,而且沒有立即放開手指)。對於長按事件,畫面底部會顯示小工具 (稱為 Snackbar),讓使用者知道他們擠壓檸檬的次數。這是透過showSnackbar()
方法來完成。

步驟 2:實作 clickLemonImage()
完成前一個步驟後,每當使用者輕觸圖片時,系統就會呼叫 clickLemonImage()
方法。這個方法負責將應用程式從目前狀態移至下一個狀態,並視需要更新變數。有四種可能的狀態:SELECT
、SQUEEZE
、DRINK
和 RESTART
;目前狀態會以 lemonadeState
變數呈現。這個方法需要針對每個狀態完成不同動作。
SELECT
:轉換為 SQUEEZE
狀態,透過呼叫 pick()
方法並將 squeezeCount
(使用者擠壓檸檬的次數) 設為 0 來設定 lemonSize
(需要擠壓的次數)。SQUEEZE
:將 squeezeCount
增加 1,並將 lemonSize
減少 1。別忘了檸檬需要不同次數的擠壓,應用程式才會轉換其狀態。只有在新的 lemonSize
等於 0 時,才轉換至 DRINK
狀態。否則應用程式應保持在 SQUEEZE
狀態。DRINK
:轉換為 RESTART
狀態,並將 lemonSize
設為 -1。RESTART
:切換回 SELECT
狀態。
處理完所有更新和狀態轉換後,請務必呼叫 setViewElements()
,根據新狀態更新使用者介面。
步驟 3:實作 setViewElements()
setViewElements()
方法負責根據應用程式的狀態更新使用者介面。文字和圖片應更新為下方顯示的值,以符合 lemonadeState
。
SELECT:
- 文字:按一下即可選取檸檬!
- 圖片:
R.drawable.lemon_tree
SQUEEZE:
文字:按一下即可擠檸檬汁
圖片:R.drawable.lemon_squeeze
DRINK:
文字:按一下即可喝檸檬水!
圖片:R.drawable.lemon_drink
RESTART:
文字:按一下即可重新開始!
圖片:R.drawable.lemon_restart
如何使用字串資源
資源可用於定義顏色、圖片、版面配置、選單和字串值。這種做法的好處是沒有硬式編碼。這些資源檔案中定義了所有內容,您可以在應用程式的程式碼中參照。這些資源最簡單 (且最常見) 的使用方式是使用字串資源,允許具有彈性的本地化文字。
字串或靜態文字可儲存在稱為 strings.xml
的個別檔案中,strings.xml
位於 res
資料夾的值子資料夾內。
針對您想要在應用程式中顯示的每段文字 (即按鈕標籤或 TextView
內的文字),您必須先定義 res/values/strings.xml
檔案中的文字。每個項目都是索引鍵
(代表文字 ID) 和值
(文字本身)。
舉例來說,如果您想讓按鈕顯示「Submit」(提交),請在 res/values/strings.xml 中加入以下字串資源:
1 | <?xml version="1.0" encoding="utf-8"?> |
如要直接存取程式碼中的資源,只要使用 getResources.getString()
或 getString()
方法,即可依照資源 ID R.string.submit_label
來存取相應的值。
1 | val submitText = getResources().getString(R.string.submit_label) |
如要直接將字串資源中的文字設定為 TextView
,您可以呼叫 TextView
物件上的 setText()
,並傳入資源 ID。
1 | val infoTextView: TextView = findViewById(R.id.info_textview) |
字串資源也可以包含特殊字元,以便設定文字格式。舉例來說,可能會有字串資源可讓您將其他文字插入字串。
1 | <string name="ingredient_tablespoon">%1$d 歲是 %2$s 的年齡</string> |
在程式碼中,您可以透過傳遞引數來存取字串資源,並設定字串資源的格式。
1 | getResources().getString(R.string.ingredient_tablespoon, 3, "Tina") |
- 宣告字串資源時,每個引數都會
依照顯示的順序編號 (1、2 等)
,並以字母表示不同類型 (d 代表小數,s 代表字串等等)
。正確類型的引數可傳遞至 getString() 的呼叫。
輸出結果:
1 | 3 歲是 Tina 的年齡 |
執行應用程式
完成結果如下所示:

測試應用程式
- 測試套件(Test Suite) - 包含所有「測試案例」的目標(target)。
- 測試案例(Test Case) - 這個類別包含相關功能的個別測試 (Lemonade 應用程式只有一個測試案例,但更大型的應用程式通常會有更多測試案例)。
- 測試(Test) - 用來測試特定項目的函式。
測試案例可以有多個測試,且專案的測試套件可以有多個測試案例。
執行測試
若是單一測試案例,請開啟測試案例類別,然後按一下類別宣告左側的綠色箭頭。然後,從選單中選取「Run」選項。
如果您有多個測試案例,也可以執行整個測試套件。就像執行應用程式一樣,您可以在「Run」選單中找到這個選項。
請注意,Android Studio 會預設為您所執行的最後一個目標 (應用程式、測試目標等),因此如果選單仍顯示「Run」>「Run ‘app’」,您可以依序選取「Run」>「Run」以執行測試目標。
然後從彈出式選單中選擇測試目標。
測試結果: