Tina Tang's Blog

在哪裡跌倒了,就在哪裡躺下來

0%

Android筆記(8)-專案:Lemonade應用程式

使用單元 1 中學到的技能,建構簡單的 Lemonade 應用程式。

學習目標

  • 在 Google 上搜尋您在應用程式中不認得的字詞、錯誤訊息和程式碼片段。
  • 測試程式碼、解讀錯誤,然後變更程式碼並重複測試。
  • 回去閱讀先前在 Android 基本概念單元 1 中的內容,溫故知新。
  • 將您知道可順利執行的程式碼 (例如專案內提供的程式碼,或是您先前在單元 1 中學到的其他應用程式的解決方案程式碼) 與您編寫的程式碼進行比對。

應用程式總覽

我們將建立簡單的互動式行動應用程式,讓您可以使用該應用程式榨取一杯檸檬汁。

成品 Lemonade 應用程式將由單一畫面組成。使用者初次啟動應用程式時,系統會提示使用者輕觸檸檬樹的圖片,藉此挑選檸檬。

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

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

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

這款應用程式的設計簡單,且提供單一活動。應用程式的不同狀態 (使用者選取檸檬、擠壓檸檬、喝檸檬汁、以及最後的空杯) 都會以「狀態機器」呈現。

雖然這聽起來像是空泛的理論術語,但這僅表示應用程式的狀態 (也就是要向使用者顯示哪些文字和圖片) 是取決於包含應用程式狀態的變數 (select 和 squeeze等等)。系統會一併更新應用程式的狀態會連同任何其他必要的變數,並在完成所有更新後分別設定使用者介面 (設定圖片和文字)。

系統已為您定義應用程式狀態的所有變數。您的工作是建構應用程式的版面配置並實作邏輯,讓使用者介面按預期在每個狀態之間轉換。


測試程式碼

對於 Lemonade 應用程式 (以及日後的專案),系統會提供一些自動化測試,讓您驗證程式碼是否可如預期般運作。Lemonade 應用程式的範例專案包含幾項測試,您可以執行測試,以確認是否已正確實作邏輯。


下載專案程式碼

資料夾名稱是 android-basics-kotlin-lemonade-app。在 Android Studio 中開啟專案時,請選取這個資料夾。

範例程式碼網址:

https://github.com/google-developer-training/android-basics-kotlin-lemonade-app

具有範例程式碼的分支版本名稱:main

然後在 Android Studio 中開啟剛才下載完成的專案


建立使用者介面

Lemonade 應用程式只需要基本的版面配置;您只需要兩個檢視畫面,就能實作所有功能。

  1. 為使用者提供操作說明的 TextView
  2. 根據應用程式目前狀態 (例如要擠壓的檸檬) 顯示圖形的 ImageView

您的目標是運用您掌握的版面配置編輯器知識,建構如下版面配置:兩個檢視畫面都在畫面中央,且 TextView 位於 ImageView 上方。

實際完成畫面:


讓應用程式與使用者互動

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

您必須實作下列三項基本工作,才能讓檸檬汁應用程式正常運作。

  1. 設定 lemonImage ImageView 以回應使用者輸入的內容。
  2. 實作 clickLemonImage() 以更新應用程式的狀態。
  3. 實作 setViewElements(),以根據應用程式目前的狀態更新使用者介面。
步驟 1:設定 ImageView

輕觸圖片檢視畫面後,應用程式就會從一個狀態切換成其他狀態。在 onCreate() 結尾,需要設定兩個事件監聽器。

  1. setOnClickListener() 應更新應用程式的狀態。方法是 clickLemonImage()
  2. setOnLongClickListener() 會回應使用者長按圖片的事件 (例如,使用者輕觸圖片,而且沒有立即放開手指)。對於長按事件,畫面底部會顯示小工具 (稱為 Snackbar),讓使用者知道他們擠壓檸檬的次數。這是透過 showSnackbar() 方法來完成。
步驟 2:實作 clickLemonImage()

完成前一個步驟後,每當使用者輕觸圖片時,系統就會呼叫 clickLemonImage() 方法。這個方法負責將應用程式從目前狀態移至下一個狀態,並視需要更新變數。有四種可能的狀態:SELECTSQUEEZEDRINKRESTART;目前狀態會以 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
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello!</string>
<string name="submit_label">Submit</string>
</resources>

如要直接存取程式碼中的資源,只要使用 getResources.getString()getString() 方法,即可依照資源 ID R.string.submit_label 來存取相應的值。

1
val submitText = getResources().getString(R.string.submit_label)

如要直接將字串資源中的文字設定為 TextView,您可以呼叫 TextView 物件上的 setText(),並傳入資源 ID。

1
2
3
val infoTextView: TextView = findViewById(R.id.info_textview)

infoTextView.setText(R.string.info_text)

字串資源也可以包含特殊字元,以便設定文字格式。舉例來說,可能會有字串資源可讓您將其他文字插入字串。

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」以執行測試目標。

然後從彈出式選單中選擇測試目標。

測試結果: