專案:Lemonade 應用程式

透過集合功能整理內容 你可以依據偏好儲存及分類內容。

1. 事前準備

本程式碼研究室將介紹一款您將自行建構的新應用程式,稱為「Lemonade」。本程式碼研究室將引導您逐步完成專案,包括在 Android Studio 中進行設定和測試。

本程式碼研究室與本課程中的其他部分不同。與先前的程式碼研究室不同,本程式碼研究室的目的並不是 逐步說明如何建構應用程式,而是設定一個您能夠獨立完成的專案,並提供指示向您說明如何自行完成應用程式及進行自我檢查。

我們改為一併在您將下載的應用程式中提供測試套件,而非解決方案程式碼。您將在 Android Studio 中執行這些測試 (我們稍後會在本程式碼研究室中說明),並且查看程式碼是否成功。這可能需要多試幾次,即使是專業開發人員也很難第一次嘗試就通過所有測試!程式碼通過所有測試後,您就能將這項專案視為完成。

我們瞭解您或許只是想要用於檢查的解決方案而已。我們特意不提供解決方案程式碼,因為我們希望您能透過練習感受身為專業開發人員的感覺。您可能會需要用到較不嫻熟的其他技能,例如:

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

乍看之下可能很困難,但我們百分之百相信如果您能夠完成單元 1,您就已經準備好進行這項專案。請按照自己的步調進行,不要放棄,我們對您有信心。

必要條件

  • 此專案適用於已完成 Kotlin 課程中 Android 基本概念單元 1 的使用者。

建構項目

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

軟硬體需求

  • 已安裝 Android Studio 的電腦。

2. 應用程式總覽

歡迎參與「專案:Lemonade 應用程式」!

我們已將您召集至團隊中,協助我們實現製作數位檸檬水的願景。我們目標是建立簡單的互動式行動應用程式,讓您可以使用該應用程式榨取一杯檸檬汁。您可以將這個視為一個譬喻,或是趣味十足度過時光的方式!

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

1ce5b75b513d63c9.png

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

fb63b41d58a83af7.png

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

f8882c1688a0e3e7.png

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

951918f0c2d0464.png

這款應用程式的設計簡單,且提供單一活動。應用程式的不同狀態 (使用者選取檸檬、擠壓檸檬、喝檸檬汁、以及最後的空杯) 都會以「狀態機器」呈現。雖然這聽起來像是空泛的理論術語,但這僅表示應用程式的狀態 (也就是要向使用者顯示哪些文字和圖片) 是取決於包含應用程式狀態的變數 (selectsqueeze等等)。系統會一併更新應用程式的狀態會連同任何其他必要的變數,並在完成所有更新後分別設定使用者介面 (設定圖片和文字)。

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

測試程式碼

對於 Lemonade 應用程式 (以及日後的專案),系統會提供一些自動化測試,讓您驗證程式碼是否可如預期般運作。

確切來說,自動測試是什麼?在軟體開發中,您可以將「測試」視為程式碼,驗證其他程式碼是否可正常運作。方法是檢查輸出 (例如畫面上使用者介面元素的內容),看看以輸入為根據是否合理 (稱為「測試案例」)。Lemonade 應用程式的範例專案包含幾項測試,您可以執行測試,以確認是否已正確實作邏輯。本文稍後會詳細說明測試。您現在可以下載範例程式碼,並開始建構 Lemonade 應用程式了。

3. 開始操作

下載專案程式碼

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

如要取得這個程式碼研究室的程式碼,並在 Android Studio 中開啟,請按照下列步驟操作:

取得程式碼

  1. 按一下所提供的網址。系統會在瀏覽器中開啟專案的 GitHub 頁面。
  2. 檢查並確認分支版本名稱符合程式碼研究室中指定的分支版本名稱。例如,在下列螢幕截圖中,分支版本名稱為「main」(主要)。

8cf29fa81a862adb.png

  1. 在專案的 GitHub 頁面中,按一下「Code」按鈕,畫面上會出現彈出式視窗。

1debcf330fd04c7b.png

  1. 在彈出式視窗中,按一下「Download ZIP」按鈕,將專案儲存至電腦。等待下載作業完成。
  2. 在電腦中找到該檔案 (可能位於「Downloads」資料夾中)。
  3. 按兩下 ZIP 檔案,將檔案解壓縮。這項操作會建立含有專案檔案的新資料夾。

在 Android Studio 中開啟專案

  1. 啟動 Android Studio。
  2. 在「Welcome to Android Studio」視窗中,按一下「Open」

d8e9dbdeafe9038a.png

注意:如果 Android Studio 已開啟,請改為依序選取「File」>「Open」選單選項。

8d1fda7396afe8e5.png

  1. 在檔案瀏覽器中,前往已解壓縮的專案資料夾所在的位置 (可能位於「Downloads」資料夾中)。
  2. 按兩下該專案資料夾。
  3. 等待 Android Studio 開啟專案。
  4. 按一下「Run」按鈕 8de56cba7583251f.png 即可建構並執行應用程式,請確認應用程式的建構符合預期。

請花點時間熟悉範例專案。請特別留意 MainActivity.kt 檔案。

4181c13884715771.png

MainActivity.kt 中,您會看到多個變數,用來呈現應用程式目前的狀態。在接下來的步驟中,您會使用這些變數讓應用程式與使用者互動。雖然這裡的程式碼數量可能會讓人感到頭昏腦脹,但您不需要修改任何未標示 TODO 的程式碼。我們會在以下頁面中提供特定指示。

您也會發現,專案中包含另一個套件 com.example.lemonade (androidTest)

a0c593c77b323c15.png

這包含了一些自動化測試,讓您用來驗證您在 MainActivity.kt 中實作的功能是否正確。稍後會再詳細說明。您現在可以開始透過使用者介面建構應用程式。

4. 建立使用者介面

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

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

您會在 activity_main.xml 中建立這個版面配置。

554c5e1ae9ec2e42.png

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

54581304e678827c.png

5. 讓應用程式與使用者互動

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

b6c5858a42dec80.png

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

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

逐一檢查各項工作。

步驟 1:設定 ImageView

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

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

b07b78c6b607e94d.png

在下一個步驟中,您將實作變更應用程式狀態的邏輯。

步驟 2:實作 clickLemonImage()

完成前一個步驟後,每當使用者輕觸圖片時,系統就會呼叫 clickLemonImage() 方法。這個方法負責將應用程式從目前狀態移至下一個狀態,並視需要更新變數。有四種可能的狀態:SELECTSQUEEZEDRINKRESTART;目前狀態會以 lemonadeState 變數呈現。這個方法需要針對每個狀態完成不同動作。

  1. SELECT:轉換為 SQUEEZE 狀態,透過呼叫 pick() 方法並將 squeezeCount (使用者擠壓檸檬的次數) 設為 0 來設定 lemonSize (需要擠壓的次數)。
  2. SQUEEZE:將 squeezeCount 增加 1,並將 lemonSize 減少 1。別忘了檸檬需要不同次數的擠壓,應用程式才會轉換其狀態。只有在新的 lemonSize 等於 0 時,才轉換至 DRINK 狀態。否則應用程式應保持在 SQUEEZE 狀態。
  3. DRINK:轉換為 RESTART 狀態,並將 lemonSize 設為 -1。
  4. 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

如何使用字串資源

在 Android 中,幾乎所有內容都是資源。定義您可以在應用程式中存取的資源,是 Android 開發作業中不可或缺的一環。

資源可用於定義顏色、圖片、版面配置、選單和字串值。這種做法的好處是沒有硬式編碼。這些資源檔案中定義了所有內容,您可以在應用程式的程式碼中參照。這些資源最簡單 (且最常見) 的使用方式是使用字串資源,允許具有彈性的本地化文字。

字串或靜態文字可儲存在稱為 strings.xml 的個別檔案中,strings.xml 位於 res 資料夾的值子資料夾內。

b65ed762eea87f2f.png

針對您想要在應用程式中顯示的每段文字 (即按鈕標籤或 TextView 內的文字),您必須先定義 res/values/strings.xml 檔案中的文字。每個項目都是索引鍵 (代表文字 ID) 和值 (文字本身)。舉例來說,如果您想讓按鈕顯示「Submit」(提交),請在 res/values/strings.xml 中加入以下字串資源:

<?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 來存取相應的值。

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

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

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

infoTextView.setText(R.string.info_text)

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

<string name="ingredient_tablespoon">%1$d tbsp of %2$s</string>

在程式碼中,您可以透過傳遞引數來存取字串資源,並設定字串資源的格式。

getResources().getString(R.string.ingredient_tablespoon, 2, "cocoa powder")

宣告字串資源時,每個引數都會依照顯示的順序編號 (12 等),並以字母表示不同類型 (d 代表小數,s 代表字串等等)。正確類型的引數可傳遞至 getString() 的呼叫。

2 tbsp of cocoa powder

詳情請參閱字串資源說明文件

6. 執行應用程式

建立應用程式的使用者介面並實作主要活動後,就可以查看實際的工作成果。使用「Run」>「Run ‘app'」選單來執行應用程式,模擬器隨即啟動。

1bb3bc95726dde79.png

應用程式現在應該具備完整的互動功能,您應該可以輕觸圖片檢視畫面來切換狀態。

42feefe9ebcf879c.png

當螢幕上顯示檸檬時,您也可以長按 (按住) ImageView,以查看畫面底部的 Snackbar,上面會顯示已擠壓檸檬幾次。請花一點時間執行應用程式幾次,執行過所有的狀態。然後休息一下,辛苦了!

7. 測試操作說明

測試應用程式

您已完成 Lemonade 應用程式的實作,但在專業軟體開發作業中,撰寫程式碼之後通常還有其他步驟。除了應用程式的程式碼以外,專業品質的應用程式還包括測試程式碼,可確認程式碼是否能正常運作,並確保程式碼的變更不會造成新的錯誤,這個過程稱為自動化測試。雖然自動化測試教學不在這個專案的涵蓋範圍內,但 Lemonade 應用程式會隨附一些測試,協助您確認是否已正確實作專案。您可以藉此進行自我評分,查看是否已達到所有專案要求,以及應用程式是否需要進行任何變更。

「測試」是什麼?測試指的是 Android Studio 專案中的程式碼片段,這些程式碼片段會執行應用程式的部分程式碼,根據應用程式的程式碼是否正常運作,測試會得到「通過」或「失敗」的結果。

該如何尋找並執行應用程式的測試?您可以在測試「target」中找到 Lemonade 應用程式的測試。「目標」是軟體開發詞彙,適用於結合再一起的類別組合。舉例來說,Lemonade 應用程式存在於名為「應用程式」的目標中,而測試則位於「LemonadeTests」目標中。雖然 LemonadeTests 目標可以從應用程式目標存取程式碼,但兩者是完全獨立的,應用程式的程式碼不含任何測試程式碼。

55f884303707e1c3.png

在「Android」檢視畫面中查看檔案時,測試目標會顯示應用程式的套件名稱,但會包含 (androidTest)。

參照測試程式碼時也有一些需要知道的重要詞彙。

  • 測試套件 - 包含所有「測試案例」的目標。
  • 測試案例 - 這個類別包含相關功能的個別測試 (Lemonade 應用程式只有一個測試案例,但更大型的應用程式通常會有更多測試案例)。
  • 測試 - 用來測試特定項目的函式。

測試案例可以有多個測試,且專案的測試套件可以有多個測試案例。

執行測試

如要執行測試,請執行下列其中一項操作:

若是單一測試案例,請開啟測試案例類別,然後按一下類別宣告左側的綠色箭頭。然後,從選單中選取「Run」選項。這麼做將會執行測試案例中的所有測試。

6c7b133bcc38ce87.png

您通常只需要執行一項測試,例如只有一個測試失敗,另一個則通過測試。執行單一測試的做法,與執行整個測試案例一樣。使用綠色箭頭並選取「Run」選項。

59690e06230bf1e4.png

如果您有多個測試案例,也可以執行整個測試套件。就像執行應用程式一樣,您可以在「Run」選單中找到這個選項。

ed1e07d2488ac446.png

請注意,Android Studio 會預設為您所執行的最後一個目標 (應用程式、測試目標等),如果選單仍顯示「Run」>「Run ‘app'」,您可以依序選取「Run」>「Run」以執行測試目標。

13bd962d134241aa.png

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

903c7ed01fa7cebf.png

測試執行結果會顯示在「Run」分頁標籤中。左側窗格中會顯示失敗測試清單 (如果有的話)。如果測試失敗,函式名稱旁邊會標上紅色驚嘆號;通過的測試會以綠色勾號標示。

37c73c4a656622af.png

如果測試失敗,文字輸出會提供相關資訊,協助您修正導致測試失敗的問題。

92f3c8219c03651d.png

例如,在上述錯誤訊息中,測試會檢查 TextView 是否使用了特定字串資源。然而,測試失敗了。「Expected」和「Got」之後的文字不相符,代表測試預期的值與執行中應用程式的值不相符。在這個例子中,TextView 中使用的字串並非是預期的實際 squeeze_count

8. 選擇性:分享應用程式!

當您透過 Lemonade 品嚐許多杯檸檬水後,您可以將喜愛的畫面擷取下來,並且在 Twitter 上分享,展示您的學習成果。標記 @AndroidDev 並新增主題標記 #AndroidBasics