Android Kotlin基礎講座 09.1:レポジトリー
目次
タスク:レポジトリーを作成する
このタスクでは、前のタスクで実装したオフラインキャッシュを管理するためのレポジトリーを作成します。現在のRoomデータベースにはオフラインキャッシュを管理するためのロジックが含まれていません。データを挿入、取得するためのメソッドのみです。ネットワークリザルトを読み取り、データベースを最新の状態にキープするためのロジックはレポジトリーが持つことになります。
ステップ1:レポジトリーを追加する
- repository/VideoRepository.kt内にVideosRepositoryクラスを作成してください。このクラスのコンストラクタのパラメーターにDaoメソッドにアクセスするためのVideosDatabaseを渡します。
/**
* Repository for fetching devbyte videos from the network and storing them on disk
*/
class VideosRepository(private val database: VideosDatabase) {
}
- VidesRepositoryクラス内に、引数を持たず、何も返さないrefreshVideos()というメソッドを追加してください。このメソッドはオフラインキャッシュをリフレッシュするために使われるAPIになります。
- refreshVideos()をsuspend関数にしてください。refreshVideos()はデータベース操作を行うので、コルーチンから呼び出される必要があるためです。
Note: Android上のデータベースはファイルシステム、またはディスクに保存されます。また保存するためにI/Oディスクを実行する必要があります。I/Oディスク、つまりディスクの読み込み、および書き込みは重く、現在のスレッドをそれらの動作が終わるまでブロックしてしまいます。このために、I/OディスクはI/Oディスパッチャー内で動かす必要があります。このディスパッチャーはI/OタスクによるブロッキングをwithContext (Dispatchers.IO){…}を使って、スレッドの共有プールにオフロードするように設計されています。
- refreshVideos()メソッド内で、コルーチンコンテキストをDispatchers.IOに切り替えて、ネットワークおよびデータベース操作を行うようにします。
/**
* Refresh the videos stored in the offline cache.
*
* This function uses the IO dispatcher to ensure the database insert database operation
* happens on the IO dispatcher. By switching to the IO dispatcher using `withContext` this
* function is now safe to call from any thread including the Main thread.
*
*/
suspend fun refreshVideos() {
withContext(Dispatchers.IO) {
}
}
- withContextブロック内で、RetrofitサービスインスタンスであるDevByteNetworkを使って、ネットワークからDevByteの動画のプレイリストを読み込みます。
val playlist = DevByteNetwork.devbytes.getPlaylist()
- refreshVideos()メソッド内、ネットワークからプレイリストを読み取るコードの後で、Roomデータベースにプレイリストを保存します。
プレイリストを保存するには、VideosDatabaseオブジェクトであるdatabaseを使います。insertAll DAOメソッドを呼び出し、ネットワークから取得したplaylistを渡してください。asDatabaseModel()拡張関数を使って、playlistをデータベースオブジェクトにマッピングします。
database.videoDao.insertAll(playlist.asDatabaseModel())
- こちらが最終的なrefreshVideosメソッドです。これが呼び出された時にトラックできるように、ログを追加しています。
suspend fun refreshVideos() {
withContext(Dispatchers.IO) {
Timber.d("refresh videos is called");
val playlist = DevByteNetwork.devbytes.getPlaylist()
database.videoDao.insertAll(playlist.asDatabaseModel())
}
}
ステップ2:データベースからデータを取得する
このステップでは、LiveDataオブジェクトを作成して、データベースから動画のプレイリストを読み込みます。このLiveDataオブジェクトはデータベースが更新されたときに自動で更新されます。取付けられたフラグメントやアクティビティは常に新しい値でリフレッシュされます。
- VideosRepositoryクラス内で、DevByteVideoオブジェクトのリストを保持するためのvideosというLiveDataオブジェクトを宣言してください。
- database.videoDaoを使って、videosオブジェクトを初期化してください。getVideos() DAOメソッドを呼び出します。getVideos()メソッドはDevByteVideoオブジェクトではなく、databaseオブジェクトのリストを返すので、Android Studioは”type mismatch(型不一致)”エラーを投げます。
val videos: LiveData<List<DevByteVideo>> = database.videoDao.getVideos()
- このエラーを解消するために、Trasformations.mapを使ってdatabaseオブジェクトのリストをdomainオブジェクトのリストに変換してください。asDomainModel()関数を使います。
復習: Transformations.mapメソッドは変換関数を使ってLiveDataオブジェクトを他のLiveDataオブジェクトに変換します。transformationsはアクティビティやフラグメントが返されたLiveDataプロパティを監視しているときにのみ使えます。
val videos: LiveData<List<DevByteVideo>> = Transformations.map(database.videoDao.getVideos()) {
it.asDomainModel()
}
これでアプリにレポジトリを実装することができました。次のタスクでは、シンプルなリフレッシュ手法を使ってローカルデータベースを最新の状態にキープします。