1. 始める前に
この Codelab では、Forage という、自分でビルドする新しいアプリを紹介します。また、Android Studio 内でのプロジェクトのセットアップやテストなど、Forage アプリ プロジェクトを完了するための手順についても説明します。
前提条件
- このプロジェクトは、「Kotlin を用いた Android の基本」コースのユニット 5 を修了した受講者を対象としています。
作成するアプリの概要
- エンティティ、DAO、ViewModel、データベース クラスを実装して、Room による永続性を既存のアプリに追加します。
必要なもの
- Android Studio がインストールされているパソコン
2. 完成したアプリの概要
完成した Forage アプリでは、自然の中で採集したもの(食糧など)を記録できます。このデータは、Room を使用してセッション間で保持されます。Room に関する知識を利用し、データベースの読み取り、書き込み、更新、削除の操作を行って、Forage アプリに永続性を実装します。完成したアプリとその機能については以下で説明します。
アプリを初めて起動すると、採集したものを表示するリサイクラー ビューを含む空の画面が表示され、その右下に、新しいアイテムを追加するためのフローティング ボタンが表示されます。
新しいアイテムを追加するときは、名前、見つけた場所、その他のメモを指定できます。今がその食材の旬であるかどうかについてのチェックボックスもあります。
追加されたアイテムは、最初の画面のリサイクラー ビューに表示されます。
アイテムをタップすると詳細画面になり、名前、場所、メモが表示されます。
フローティング ボタンもプラス記号から編集アイコンに変わります。このボタンをタップすると、名前、場所、メモ、「旬」のチェックボックスを編集できる画面になります。削除ボタンをタップすると、そのアイテムがデータベースから削除されます。
このアプリの UI 部分はすでに実装されていますが、ここでのタスクは、Room の知識を利用して永続性を実装し、アプリがデータベースに対しアイテムの読み取り、書き込み、更新、削除を行えるようにすることです。
3.始める
プロジェクト コードをダウンロードする
フォルダ名は android-basics-kotlin-forage-app
です。Android Studio でプロジェクトを開くときは、このフォルダを選択してください。
この Codelab のコードを取得して Android Studio で開く手順は次のとおりです。
コードを取得する
- 指定された URL をクリックします。プロジェクトの GitHub ページがブラウザで開きます。
- プロジェクトの GitHub ページで、[Code] ボタンをクリックすると、ダイアログが表示されます。
- ダイアログで、[Download ZIP] をクリックして、プロジェクトをパソコンに保存します。ダウンロードが完了するまで待ってください。
- パソコンに保存したファイルを見つけます([ダウンロード] フォルダなど)。
- ZIP ファイルをダブルクリックして展開します。プロジェクト ファイルが入った新しいフォルダが作成されます。
Android Studio でプロジェクトを開く
- Android Studio を起動します。
- [Welcome to Android Studio] ウィンドウで [Open an existing Android Studio project] をクリックします。
注: Android Studio がすでに開いている場合は、メニューから [File] > [New] > [Import Project] を選択します。
- [Import Project] ダイアログで、展開したプロジェクト フォルダがある場所([ダウンロード] フォルダなど)に移動します。
- そのプロジェクト フォルダをダブルクリックします。
- Android Studio でプロジェクトが開くまで待ちます。
- 実行ボタン をクリックし、アプリをビルドして実行します。正常にビルドされたことを確認します。
- [Project] ツール ウィンドウでプロジェクト ファイルを見て、アプリがどのように設定されているかを確認します。
4. Room を使用するようにプロジェクトを設定する
Forageable エンティティを定義する
プロジェクトには、アプリのデータを定義する Forageable
クラスがすでに存在しています(model.Forageable.kt)。このクラスには、id
、name
、address
、inSeason
、notes
といったプロパティがあります。
data class Forageable(
val id: Long = 0,
val name: String,
val address: String,
val inSeason: Boolean,
val notes: String?
)
ただし、このクラスを使用して永続データを保存するには、Room エンティティに変換する必要があります。
- テーブル名
"forageable_database"
で@Entity
を使用してクラスにアノテーションを付けます。 id
プロパティを主キーにします。主キーは自動生成されます。inSeason
プロパティの列名を"in_season"
に設定します。
DAO を実装する
ForageableDao
(data.ForageableDao.kt)では、ご想像どおり、ビューモデルからアクセスするデータベースに対して読み書きするメソッドを定義します。DAO はデベロッパーが定義するインターフェースにすぎないため、こうしたメソッドを実装するためのコードを実際に記述する必要はありません。代わりに Room アノテーションを使用し、必要に応じて SQL クエリを指定する必要があります。
ForageableDao
インターフェース内に、5 つのメソッドを追加する必要があります。
- データベース内のすべての行について
Flow<List<Forageable>>
を返すgetForageables()
メソッド - 指定された
id
に一致するFlow<Forageable>
を返すgetForageable(id: Long)
メソッド - 新しい
Forageable
をデータベースに挿入するinsert(forageable: Forageable)
メソッド - 既存の
Forageable
をパラメータとして受け取り、それに応じて行を更新するupdate(forageable: Forageable)
メソッド Forageable
をパラメータとして受け取り、データベースから削除するdelete(forageable: Forageable)
メソッド
ViewModel を実装する
ForageableViewModel
(ui.viewmodel.ForageableViewModel.kt)は部分的に実装されていますが、実際にデータを読み書きできるように DAO メソッドにアクセスする機能を追加する必要があります。ForageableViewModel
を実装する手順は次のとおりです。
ForageableDao
のインスタンスをクラス コンストラクタのパラメータとして渡す必要があります。- DAO を使用して
Forageable
エンティティのリスト全体を取得し、結果をLiveData
に変換するLiveData<List<Forageable>>
型の変数を作成します。 - パラメータとして id(
Long
型)を取り、DAO のgetForageable()
メソッドを呼び出して結果をLiveData
に変換することでLiveData<Forageable>
を返すメソッドを作成します。 addForageable()
メソッドで、viewModelScope
を使用してコルーチンを起動し、DAO を使用してForageable
インスタンスをデータベースに挿入します。updateForageable()
メソッドで、DAO を使用してForageable
エンティティを更新します。deleteForageable()
メソッドで、DAO を使用してForageable
エンティティを更新します。ForageableDao
コンストラクタ パラメータで、ForageableViewModel
のインスタンスを作成できるViewModelFactory
を作成します。
Database クラスを実装する
ForageDatabase
(data.ForageDatabase.kt
)クラスは、エンティティと DAO を実際に Room に公開します。説明に沿って ForageDatabase
クラスを実装します。
- エンティティ:
Forageable
- バージョン:
1
- exportSchema:
false
ForageDatabase
クラス内に、ForageableDao
を返す抽象関数を含めます。ForageDatabase
クラス内で、INSTANCE
というプライベート変数と、ForageDatabase
シングルトンを返すgetDatabase()
関数を使用してコンパニオン オブジェクトを定義します。
BaseApplication
クラスで、遅延初期化を使用してForageDatabase
インスタンスを返すdatabase
プロパティを作成します。
5. フラグメントのデータの保持と読み取り
エンティティ、DAO、ビューモデルを設定し、Room に公開するデータベース クラスを定義したら、あとはビューモデルにアクセスするように Fragment を変更するだけです。アプリの画面ごとに 1 つずつ、合わせて 3 つのファイルを変更する必要があります。
採集物リスト
採集物リスト画面で必要となるものは 2 つだけあります。ビューモデルへの参照と、採集物の完全なリストへのアクセスです。ui.ForageableListFragment.kt で次のタスクを行います。
- クラスにはすでに
viewModel
プロパティがあります。ただし、前のステップで定義したファクトリは使用していません。まず、この宣言をリファクタリングしてForageableViewModelFactory
を使用する必要があります。
private val viewModel: ForageableViewModel by activityViewModels {
ForageableViewModelFactory(
(activity?.application as BaseApplication).database.foragableDao()
)
}
- 次に、
onViewCreated()
でviewModel
のallForageables
プロパティを監視し、必要に応じてアダプターでsubmitList()
を呼び出して、リストにデータを入力します。
採集物詳細画面
ui/ForageableDetailFragment.kt の詳細リストとほぼ同じ処理を行います。
ForageableViewModelFactory
が正しく初期化されるようにviewModel
プロパティを変換します。onViewCreated()
で、id
を渡してビューモデルでgetForageable()
を呼び出し、Forageable
エンティティを取得します。ライブデータを確認し、結果をforageable
プロパティに設定してから、bindForageable()
を呼び出して UI を更新します。
採集物画面の追加と編集
最後に、ui.AddForageableFragment.kt で同様の処理を行う必要があります。なお、この画面ではエンティティの更新と削除も行います。ただし、ビューモデルのこうしたメソッドは、すでに正しい場所で呼び出されています。このファイルに必要な変更は 2 つだけです。
- 再度、
viewModel
プロパティをリファクタリングしてForageableViewModelFactory
を使用します。 onViewCreated()
で、削除ボタンの表示を設定する前の if ステートメント ブロックで、id
を渡してビューモデルでgetForageable()
を呼び出し、結果をforageable
プロパティに設定します。
フラグメントで行う必要がある作業は以上です。これでアプリを実行できるようになり、すべての永続化機能が動作していることがわかるはずです。
6. テスト手順
テストを実行する
テストを実行するには、次のいずれかを行います。
テストケースが 1 つの場合は、テストケース クラス PersistenceInstrumentationTests.kt
を開いて、クラス宣言の左側にある緑色の矢印をクリックします。メニューから [Run] オプションを選択します。これにより、テストケース内のすべてのテストが実行されます。
多くの場合、1 つのテストを実行するだけで済みます。たとえば、失敗したテストが 1 つしかなく、他のテストには合格している場合などです。テストケース全体を実行するときと同じように、1 つのテストを実行できます。緑色の矢印をクリックして [Run] オプションを選択します。
複数のテストケースがある場合は、テストスイート全体を実行することもできます。アプリを実行する場合と同様に、このオプションは [Run] メニューにあります。
Android Studio は、デフォルトでは最後に実行したターゲット(アプリやテスト ターゲットなど)を実行するため、メニューに [Run] > [Run 'app'] と表示されている場合は、[Run] > [Run] を選択してテスト ターゲットを実行できます。
ポップアップ メニューからテスト ターゲットを選択します。