プロジェクト: Lemonade アプリ

この Codelab では、Lemonade という、自分でビルドする新しいアプリを紹介します。また、Android Studio 内でのセットアップやテストなど、プロジェクトを完了するための手順についても説明します。

この Codelab は、このコースの他の Codelab とは異なります。これまでの Codelab とは異なり、この Codelab は、アプリのビルド手順を説明するチュートリアルではありません。代わりに、ユーザーが単独で完了できるプロジェクトを設定し、アプリを完成させて自分で確認する方法を紹介しています。

解答コードの代わりに、ダウンロードするアプリの一部としてテストスイートを提供しています。これらのテストを Android Studio で実行して(その方法については、後ほどこの Codelab で説明します)、コードが合格するか確認します。1 回のテストで完了するとは限りません。プロのデベロッパーでも、すべてのテストが最初のテストで合格することはほとんどないと言っていいでしょう。作成したコードがすべてのテストに合格したら、このプロジェクトは完了したとみなすことができます。

これについては、確認対象のソリューションだけがあればよいと考えるかもしれません。解答コードを提供しないのは、プロフェッショナルなデベロッパーの作業を体験していただく意図からです。そのため次のような、まだ習熟していないスキルが求められる場合があります。

  • 初めて目にする Google 用語、エラー メッセージ、アプリ内のコード
  • コードのテスト、エラーの読み取り、コードの変更と再テスト
  • Android の基本のユニット 1 にあるコンテンツに戻り、学習した内容を復習
  • 動作することがわかっているコード(プロジェクトで提供されたコード、またはユニット 1 で他のアプリについて使用した解答コード)と、作成したコードを比較

最初は大変に思えるかもしれませんが、ユニット 1 を完了できれば、このプロジェクトにも十分に対応できると確信しています。じっくりと時間をかけ、あきらめずに取り組んでください。必ずできるはずです。

前提条件

  • このプロジェクトは、Kotlin コースの「Android の基本」のユニット 1 を完了しているユーザーを対象としています。

作成するアプリの概要

  • ユニット 1 で習得したスキルを使って簡単な Lemonade アプリを作成します。

必要なもの

  • Android Studio がインストールされているパソコン

プロジェクト: Lemonade アプリへようこそ。

あなたは、デジタル上でレモネードを作るという当チームのビジョンを一緒に実現するために採用されました。プロジェクトの目標は、レモンを絞ってグラス 1 杯分のレモネードを作るという、シンプルでインタラクティブなモバイルアプリを作成することです。このアプリはメタファーとして、あるいはちょっとした暇つぶしの方法として考えてください。

完成した Lemonade アプリは 1 つの画面で構成されています。ユーザーが初めてアプリを起動すると、レモンの木の画像をタップしてレモンを選択するよう求められます。

d61077d38ce788da.png

レモンの木をタップするとレモンが表示され、レモンをタップして不特定の回数(正確な回数はランダムに生成されます)だけ「絞る」と、次の画面に移動できます。

c4897dc7432c2908.png

レモンを正確な回数タップして絞ると、レモネードを「飲む」ためのグラスの画像が表示されます。

846dd7e1b8c230c.png

レモネードをタップして飲むと、グラスが空になります。画像をもう一度タップすると最初の画面に戻り、木から別のレモンを選択できます。

9dfc622d3c2efee7.png

このアプリはシンプルさを重視してビルドされ、1 つのアクティビティにまとめられています。アプリのさまざまな状態(レモンを選択する、レモンを絞る、レモネードを飲む、最後にグラスが空になる)は、「ステートマシン」と呼ばれるもので表されます。これは難しい理論的な用語に聞こえますが、要するに、アプリの状態(ユーザーにどのテキストと画像を表示するか)が、アプリの状態(selectsqueeze など)を含む変数によって決定されるということです。アプリの状態はその他の必要な変数とともに更新され、すべての更新が完了すると UI(画像とテキストの設定)が別々に構成されます。

アプリの状態のすべての変数が、あらかじめ定義されています。このプロジェクトでは、UI が状態間で想定どおりに遷移するように、アプリのレイアウトを作成し、ロジックを実装してください。

コードをテストする

Lemonade アプリ(および今後のプロジェクト)では、コードが想定どおりに動作することを確認できる自動テストが用意されています。

自動テストとは何でしょうか。ソフトウェア開発における「テスト」は、他のコードが動作することを確認するためのコードと考えることができます。具体的には、入力(「テストケース」と呼ばれます)に対する出力(画面上の UI 要素のコンテンツなど)が適切かどうかを確認します。Lemonade アプリのスターター プロジェクトには、ロジックが適切に実装されていることを確認するために実行できるテストがいくつか含まれています。テストについては、後で詳しく説明します。まずはスターター コードをダウンロードし、Lemonade アプリの作成を始めましょう。

プロジェクト コードをダウンロードする

フォルダ名は android-basics-kotlin-lemonade-app です。Android Studio でプロジェクトを開くときは、このフォルダを選択してください。

この Codelab のコードを取得して Android Studio で開くには、以下の手順に沿って操作します。

コードを取得する

  1. 指定された URL をクリックします。プロジェクトの GitHub ページがブラウザで開きます。
  2. プロジェクトの GitHub ページで、[Code] ボタンをクリックすると、ダイアログが表示されます。

5b0a76c50478a73f.png

  1. ダイアログで、[Download ZIP] をクリックして、プロジェクトをパソコンに保存します。ダウンロードが完了するまで待ってください。
  2. パソコンに保存したファイルを見つけます([ダウンロード] フォルダなど)。
  3. ZIP ファイルをダブルクリックして展開します。プロジェクト ファイルが入った新しいフォルダが作成されます。

Android Studio でプロジェクトを開く

  1. Android Studio を起動します。
  2. [Welcome to Android Studio] ウィンドウで [Open an existing Android Studio project] をクリックします。

36cc44fcf0f89a1d.png

注: Android Studio がすでに開いている場合は、メニューから [File] > [New] > [Import Project] を選択します。

21f3eec988dcfbe9.png

  1. [Import Project] ダイアログで、解凍したプロジェクト フォルダがある場所([ダウンロード] フォルダなど)に移動します。
  2. そのプロジェクト フォルダをダブルクリックします。
  3. Android Studio でプロジェクトが開かれるまで待ちます。
  4. 実行ボタン 11c34fc5e516fb1c.png をクリックして、アプリをビルドし、実行します。期待どおりにビルドされることを確認します。
  5. [Project] ツール ウィンドウでプロジェクト ファイルを見て、アプリがどのように設定されているかを確認します。

スターター プロジェクトをよく理解しておいてください。MainActivity.kt ファイルには特に注意が必要です。

187e261ddee1b032.png

MainActivity.kt には、アプリの現在の状態を表すために使用される変数がいくつか含まれています。これらの値は、後のステップでアプリをインタラクティブにするために使用します。コードの量が多く見えるかもしれませんが、TODO のマークが付いていないコードを変更する必要はありません。詳しい手順については次のページで説明します。

このプロジェクトには別のパッケージ com.example.lemonade (androidTest) も含まれています。

d68e0812be53370d.png

このパッケージには、MainActivity.kt に実装した機能が正しいことを確認するための自動テストが含まれます。これについても後で詳しく説明します。アプリの作成を始める準備が整ったので、まずはユーザー インターフェースから作成しましょう。

Lemonade アプリには基本レイアウトのみが必要です。すべての機能を実装するのに必要なのは、次の 2 つのビューだけです。

  1. TextView: ユーザーに手順を示します。
  2. ImageView: アプリの現在の状態に基づいて画像を表示します(例: 絞るためのレモン)。

このレイアウトは activity_main.xml で作成します。

da9d7b9e9e85b339.png

ここでの目標は、Layout Editor に関する知識を活かして、次のようなレイアウトを作成することです。両方のビューを画面中央に表示し、ImageView の上に TextView を配置します。

d384c5cc4d7b5634.png

レイアウトが完了したら、MainActivity.kt を開きます。ここで、アプリのロジックをすべて実装します。すでに大量のコードがあり、// TODO: のマークが付いたコメントも多数あります(下の例を参照)。このコメントに、完了すべきタスクが記述されています

d3a4d509918df93c.png

Lemonade アプリを動作させるための基本的な実装は次の 3 つです。

  1. ユーザー入力に応答する lemonImage ImageView を設定します。
  2. アプリの状態を更新する clickLemonImage() を実装します。
  3. アプリの現在の状態に基づいて UI を更新する setViewElements() を実装します。

各タスクを 1 つずつ見ていきましょう。

ステップ 1: ImageView を設定する

画像ビューをタップすると、アプリは別の状態に遷移します。onCreate() の末尾には、2 つのリスナーを設定する必要があります。

  1. setOnClickListener() は、アプリの状態を更新します。これを行うメソッドは clickLemonImage() です。
  2. setOnLongClickListener() は、ユーザーが画像を長押しするイベント(画像をタップしてすぐに指を離さない場合など)に応答します。長押しイベントでは、スナックバーと呼ばれるウィジェットが画面の下部に表示され、そこでレモンを絞った回数を確認できます。これには showSnackbar() メソッドを使用します。

54f9f0a3aa903c31.png

次のステップでは、アプリの状態を変更するロジックを実装します。

ステップ 2: clickLemonImage() を実装する

前のステップを完了したことで、ユーザーが画像をタップするたびに clickLemonImage() メソッドが呼び出されるようになりました。このメソッドは、アプリを現在の状態から次の状態に遷移させるとともに、必要に応じて変数を更新します。状態には SELECTSQUEEZEDRINKRESTART の 4 つがあり、現在の状態は lemonadeState 変数によって表されます。このメソッドでは、状態ごとに異なる処理を行う必要があります。

  1. SELECT: SQUEEZE 状態に遷移し、pick() メソッドを呼び出して lemonSize(絞る必要のある回数)を設定し、squeezeCount(ユーザーがレモンを絞った回数)を 0 に設定します。
  2. SQUEEZE: squeezeCount を 1 増やし、lemonSize を 1 減らします。squeezeCount の前に、不特定の回数だけレモンを絞る必要があります。新しい lemonSize が 0 の場合にのみ、DRINK 状態に遷移します。それ以外の場合は、アプリは SQUEEZE 状態のままになります。
  3. DRINK: RESTART 状態に遷移し、lemonSize を -1 に設定します。
  4. RESTART: SELECT 状態に戻します。

状態の更新と遷移をすべて処理したら、必ず setViewElements() を呼び出して、新しい状態に基づいて UI を更新します。

ステップ 3: setViewElements() を実装する

setViewElements() メソッドは、アプリの状態に基づいて UI を更新します。lemonadeState と一致するように、テキストと画像を以下の値で更新する必要があります。

SELECT:

  • テキスト: クリックしてレモンを選択してください。
  • 画像: R.drawable.lemon_tree

SQUEEZE:

  • テキスト: クリックしてレモンを絞ってください。
  • 画像: R.drawable.lemon_squeeze

DRINK:

  • テキスト: クリックしてレモネードを飲んでください。
  • 画像: R.drawable.lemon_drink

RESTART:

  • テキスト: クリックして最初からやり直してください。
  • 画像: R.drawable.lemon_restart

文字列リソースの使用方法

Android では、ほとんどあらゆるものがリソースになっています。アプリからアクセスできるリソースを定義することは、Android の開発で不可欠な要素です。

リソースは、色、画像、レイアウト、メニュー、文字列値などの定義に使用されます。これには、ハードコードされた部分がないという利点があります。すべてがリソース ファイルで定義され、それをアプリケーションのコード内で参照できます。リソースの中でも最もシンプルで一般的なのが、ローカライズされたテキストを柔軟に作成できる文字列リソースです。

文字列または静的テキストは、res フォルダの values サブフォルダ内にある strings.xml という別のファイルに保存できます。

65588c6102e5139.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 など)と、型を識別する文字(10 進数の場合は d、文字列の場合は s など)が付けられます。正しい型の引数は getString() の呼び出しに渡すことができます。

2 tbsp of cocoa powder

詳しくは、文字列リソースに関するドキュメントを参照してください。

アプリの UI を作成してメイン アクティビティを実装したら、実際に動作させて確認しましょう。[Run] > [Run 'app'] を選択してアプリを実行すると、エミュレータが起動します。

ae484ede4fe1dd1f.png

アプリは完全にインタラクティブな状態になり、画像ビューをタップすると状態が遷移するようになっているはずです。

3e8867f3aea54c78.png

レモンが表示されている状態で ImageView を長押しして、画面下部のスナックバーにレモンを絞った回数の合計が表示されるかも確認しましょう。時間をかけてアプリの状態を何度か遷移させて、すべての状態で問題なく動作することを確認してください。

アプリをテストする

Lemonade アプリの実装は終わりましたが、プロのソフトウェア開発では、コードを書いただけで完了とすることはめったにありません。質の高いアプリには、アプリケーション コードのほかに、コードが想定どおりに動作し、コードを変更しても新しいバグが発生しないことを確認するテストコードが含まれています。このプロセスは自動テストと呼ばれます。自動テストの詳細についてはこのプロジェクトの範囲外ですが、Lemonade アプリには、プロジェクトを正しく実装されていることを確認するのに役立つテストがいくつかバンドルされています。セルフチェックのひとつとして自動テストを使うことで、すべてのプロジェクト要件を満たしているかどうか、アプリに変更を加える必要があるかどうかを確認できます。

「テスト」とは、正確には Android Studio プロジェクトに含まれているコードブロックで、アプリのコードの一部を実行します。アプリのコードが想定どおり動作するかどうかに応じて「合格」または「不合格」となります。

Lemonade アプリのテストは、テストのターゲットにあります。ターゲットはソフトウェア開発用語で、ひとまとめにされたクラス コレクションのことです。たとえば、Lemonade アプリは「app」というターゲットに存在しますが、テストは「LemonadeTests」というターゲットに存在します。LemonadeTests ターゲットは app ターゲットのコードにアクセスできますが、これらは完全に分離されており、アプリのコードにテストコードは含まれていません。

20edcb90dca9d70b.png

[Android] ビューでファイルを表示すると、テスト ターゲットはアプリと同じパッケージ名で表示されますが、その後に「(androidTest)」という文字列が続いています。

また、テストコードに関する重要な用語がいくつかあります。

  • テストスイート - すべてのテストケースが含まれるターゲット。
  • テストケース - 関連する機能の個々のテストで構成されるクラス(Lemonade アプリのテストケースは 1 つでしたが、大規模なアプリには多くの場合、多数のテストケースが含まれています)。
  • テスト - 1 つの特定の項目をテストする関数。

1 つのテストケースに複数のテストを含めることも、プロジェクトのテストスイートに複数のテストケースを含めることもできます。

テストを実行する

テストを実行するには、次のいずれかを行います。

1 つのテストケースの場合、テストケース クラスを開き、クラス宣言の左側にある緑色の矢印をクリックします。メニューから [Run] オプションを選択します。これにより、テストケース内のすべてのテストが実行されます。

a32317d35c77142b.png

多くの場合、1 つのテストを実行するだけで済みます。たとえば、失敗したテストが 1 つしかなく、他のテストには合格している場合などです。テストケース全体を実行するときと同じように、1 つのテストを実行できます。緑色の矢印をクリックして [Run] オプションを選択します。

ac6244434cfafb60.png

複数のテストケースがある場合は、テストスイート全体を実行することもできます。アプリを実行する場合と同様に、このオプションは [Run] メニューにあります。

7a925c5e196725bb.png

Android Studio は、最後に実行したターゲット(アプリ、テスト ターゲットなど)をデフォルトで実行するため、メニューに [Run] > [Run 'app'] と表示されている場合は、[Run] > [Run] を選択してテスト ターゲットを実行します。

ee1e227446c536fe.png

ポップアップ メニューからテスト ターゲットを選択します。

d570c947769db65c.png

テストの実行結果が [Run] タブに表示されます。左側のペインに、失敗したテストのリストが表示されます(ある場合)。失敗したテストについては、関数名の横に赤い感嘆符が表示されます。合格したテストには緑色のチェックマークが表示されます。

6d68f2bf589501ae.png

テストが失敗すると、テキスト出力に、テスト失敗の原因となった問題の解決に役立つ情報が表示されます。

92f3c8219c03651d.png

たとえば、上記のエラー メッセージは、TextView が特定の文字列リソースを使用しているかどうかをテストし、失敗したことを示しています。「Expected」と「Got」の後のテキストが一致していない場合、テストで想定されている値と実行中のアプリの値が一致していないことを意味します。この例では、TextView で使用されている文字列が、テストで想定されている squeeze_count ではありません。

アプリで何回かレモネードを作ってみたら、お気に入りの画面のスクリーンショットを撮り、この Codelab で学んだ内容として Twitter で共有しましょう。その際は @AndroidDev をタグ付けし、ハッシュタグ #AndroidBasics を追加してください。