プロジェクト: Forage アプリ

1. 始める前に

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

前提条件

  • このプロジェクトは、「Kotlin を用いた Android の基本」コースのユニット 5 を修了した受講者を対象としています。

作成するアプリの概要

  • エンティティ、DAO、ViewModel、データベース クラスを実装して、Room による永続性を既存のアプリに追加します。

必要なもの

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

2. 完成したアプリの概要

完成した Forage アプリでは、自然の中で採集したもの(食糧など)を記録できます。このデータは、Room を使用してセッション間で保持されます。Room に関する知識を利用し、データベースの読み取り、書き込み、更新、削除の操作を行って、Forage アプリに永続性を実装します。完成したアプリとその機能については以下で説明します。

アプリを初めて起動すると、採集したものを表示するリサイクラー ビューを含む空の画面が表示され、その右下に、新しいアイテムを追加するためのフローティング ボタンが表示されます。

3edd87e63c387d88.png

新しいアイテムを追加するときは、名前、見つけた場所、その他のメモを指定できます。今がその食材の旬であるかどうかについてのチェックボックスもあります。

6c0c739569bb3b4f.png

追加されたアイテムは、最初の画面のリサイクラー ビューに表示されます。

bcc75e60b70320e8.png

アイテムをタップすると詳細画面になり、名前、場所、メモが表示されます。

5096995a4921dcac.png

フローティング ボタンもプラス記号から編集アイコンに変わります。このボタンをタップすると、名前、場所、メモ、「旬」のチェックボックスを編集できる画面になります。削除ボタンをタップすると、そのアイテムがデータベースから削除されます。

f8c708fed3dede1a.png

このアプリの UI 部分はすでに実装されていますが、ここでのタスクは、Room の知識を利用して永続性を実装し、アプリがデータベースに対しアイテムの読み取り、書き込み、更新、削除を行えるようにすることです。

3.始める

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

フォルダ名は android-basics-kotlin-forage-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] ツール ウィンドウでプロジェクト ファイルを見て、アプリがどのように設定されているかを確認します。

4. Room を使用するようにプロジェクトを設定する

Forageable エンティティを定義する

プロジェクトには、アプリのデータを定義する Forageable クラスがすでに存在しています(model.Forageable.kt)。このクラスには、idnameaddressinSeasonnotes といったプロパティがあります。

data class Forageable(
   val id: Long = 0,
   val name: String,
   val address: String,
   val inSeason: Boolean,
   val notes: String?
)

ただし、このクラスを使用して永続データを保存するには、Room エンティティに変換する必要があります。

  1. テーブル名 "forageable_database"@Entity を使用してクラスにアノテーションを付けます。
  2. id プロパティを主キーにします。主キーは自動生成されます。
  3. inSeason プロパティの列名を "in_season" に設定します。

DAO を実装する

ForageableDaodata.ForageableDao.kt)では、ご想像どおり、ビューモデルからアクセスするデータベースに対して読み書きするメソッドを定義します。DAO はデベロッパーが定義するインターフェースにすぎないため、こうしたメソッドを実装するためのコードを実際に記述する必要はありません。代わりに Room アノテーションを使用し、必要に応じて SQL クエリを指定する必要があります。

ForageableDao インターフェース内に、5 つのメソッドを追加する必要があります。

  1. データベース内のすべての行について Flow<List<Forageable>> を返す getForageables() メソッド
  2. 指定された id に一致する Flow<Forageable> を返す getForageable(id: Long) メソッド
  3. 新しい Forageable をデータベースに挿入する insert(forageable: Forageable) メソッド
  4. 既存の Forageable をパラメータとして受け取り、それに応じて行を更新する update(forageable: Forageable) メソッド
  5. Forageable をパラメータとして受け取り、データベースから削除する delete(forageable: Forageable) メソッド

ViewModel を実装する

ForageableViewModelui.viewmodel.ForageableViewModel.kt)は部分的に実装されていますが、実際にデータを読み書きできるように DAO メソッドにアクセスする機能を追加する必要があります。ForageableViewModel を実装する手順は次のとおりです。

  1. ForageableDao のインスタンスをクラス コンストラクタのパラメータとして渡す必要があります。
  2. DAO を使用して Forageable エンティティのリスト全体を取得し、結果を LiveData に変換する LiveData<List<Forageable>> 型の変数を作成します。
  3. パラメータとして id(Long 型)を取り、DAO の getForageable() メソッドを呼び出して結果を LiveData に変換することで LiveData<Forageable> を返すメソッドを作成します。
  4. addForageable() メソッドで、viewModelScope を使用してコルーチンを起動し、DAO を使用して Forageable インスタンスをデータベースに挿入します。
  5. updateForageable() メソッドで、DAO を使用して Forageable エンティティを更新します。
  6. deleteForageable() メソッドで、DAO を使用して Forageable エンティティを更新します。
  7. ForageableDao コンストラクタ パラメータで、ForageableViewModel のインスタンスを作成できる ViewModelFactory を作成します。

Database クラスを実装する

ForageDatabasedata.ForageDatabase.kt)クラスは、エンティティと DAO を実際に Room に公開します。説明に沿って ForageDatabase クラスを実装します。

  1. エンティティ: Forageable
  2. バージョン: 1
  3. exportSchema: false
  4. ForageDatabase クラス内に、ForageableDao を返す抽象関数を含めます。
  5. ForageDatabase クラス内で、INSTANCE というプライベート変数と、ForageDatabase シングルトンを返す getDatabase() 関数を使用してコンパニオン オブジェクトを定義します。
  1. BaseApplication クラスで、遅延初期化を使用して ForageDatabase インスタンスを返す database プロパティを作成します。

5. フラグメントのデータの保持と読み取り

エンティティ、DAO、ビューモデルを設定し、Room に公開するデータベース クラスを定義したら、あとはビューモデルにアクセスするように Fragment を変更するだけです。アプリの画面ごとに 1 つずつ、合わせて 3 つのファイルを変更する必要があります。

採集物リスト

採集物リスト画面で必要となるものは 2 つだけあります。ビューモデルへの参照と、採集物の完全なリストへのアクセスです。ui.ForageableListFragment.kt で次のタスクを行います。

  1. クラスにはすでに viewModel プロパティがあります。ただし、前のステップで定義したファクトリは使用していません。まず、この宣言をリファクタリングして ForageableViewModelFactory を使用する必要があります。
private val viewModel: ForageableViewModel by activityViewModels {
   ForageableViewModelFactory(
       (activity?.application as BaseApplication).database.foragableDao()
   )
}
  1. 次に、onViewCreated()viewModelallForageables プロパティを監視し、必要に応じてアダプターで submitList() を呼び出して、リストにデータを入力します。

採集物詳細画面

ui/ForageableDetailFragment.kt の詳細リストとほぼ同じ処理を行います。

  1. ForageableViewModelFactory が正しく初期化されるように viewModel プロパティを変換します。
  2. onViewCreated() で、id を渡してビューモデルで getForageable() を呼び出し、Forageable エンティティを取得します。ライブデータを確認し、結果を forageable プロパティに設定してから、bindForageable() を呼び出して UI を更新します。

採集物画面の追加と編集

最後に、ui.AddForageableFragment.kt で同様の処理を行う必要があります。なお、この画面ではエンティティの更新と削除も行います。ただし、ビューモデルのこうしたメソッドは、すでに正しい場所で呼び出されています。このファイルに必要な変更は 2 つだけです。

  1. 再度、viewModel プロパティをリファクタリングして ForageableViewModelFactory を使用します。
  2. onViewCreated() で、削除ボタンの表示を設定する前の if ステートメント ブロックで、id を渡してビューモデルで getForageable() を呼び出し、結果を forageable プロパティに設定します。

フラグメントで行う必要がある作業は以上です。これでアプリを実行できるようになり、すべての永続化機能が動作していることがわかるはずです。

6. テスト手順

テストを実行する

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

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

3e640ec727599a6d.png

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

8647a76419540499.png

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

7a925c5e196725bb.png

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

90d3ec5ca5928b2a.png

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

3b1a7d82a55b5f13.png