オプション: ローカルキャッシング
顧客への迅速で継続的なアクセスを保証するために、Amplify DataStoreはリモートデータのローカルキャッシュ版を採用しています。Amplify DataStoreからの移行中に、不要な複雑さを避けるために、モデルに合わせたローカルストレージソリューションを選択する必要があります。
DataStoreはAndroidの組み込みSQLiteデータベースAPIを直接使用しますが、選択するオプションはキャッシング要件によって異なる可能性があります。ライブラリの提案については、ヘルプリソースページを参照してください。
Apolloの正規化されたキャッシュ
Apollo Kotlinには、SQLiteを正規化されたキャッシュとして使用するオプションが含まれています。正規化されたキャッシュは設定が簡単で、Apolloがキャッシュから以前のクエリを再生して、遅延を改善し、帯域幅消費を削減し、オフライン中にクエリを再生できます。
正規化されたキャッシュのセットアップ手順については、Migrate DataStore to Apollo — ObserveQueryセクションを参照してください。このセクションでは依存関係の追加とキャッシュの構成について説明しています。
Roomを使用したカスタムキャッシング
キャッシュされたデータへのより豊富なアクセスが必要な高度な使用例については、Apolloが提供するキャッシュの代わりに、または追加として、独自のキャッシング層を使用できます。このアプローチの2つの一般的なライブラリはSQLDelightとRoomです。以下の例ではRoomを使用しています。
ローカルモデル
独自のキャッシュでモデルをキャッシュするには、Apollo生成モデルに対応するローカルストレージ用の別のエンティティを作成します。Roomでは、PostDetailsフラグメントに対応するエンティティは次のようになります:
@Entity(tableName = "post")data class PostEntity( @PrimaryKey val id: String, val updatedAt: String, val createdAt: String, val title: String, val content: String, val status: PostStatus, val rating: Int)その後、DAOを使用してこれらのエンティティを保存、クエリ、および変更できます:
@Daointerface PostDao { @Query("SELECT * FROM post") suspend fun getAll(): List<PostEntity>
@Query("SELECT * FROM post WHERE id = :id") suspend fun get(id: String): PostEntity
@Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insert(vararg posts: PostEntity)
@Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertAll(posts: List<PostEntity>)
@Delete suspend fun delete(post: PostEntity)}モデルマッピング
拡張関数を使用して、あるモデルタイプを別のモデルタイプにマップできます:
fun PostDetails.toLocalModel() = PostEntity( id = id, updatedAt = updatedAt, createdAt = createdAt, title = title, content = content, status = status, rating = rating)
fun PostEntity.toRemoteModel() = PostDetails( id = id, updatedAt = updatedAt, createdAt = createdAt, title = title, content = content, status = status, rating = rating)スキーマバージョンを変更する場合、DataStoreはモデルの非互換性を防ぐためにデータを破棄します。Roomでは、キャッシュされたデータを保持するためにマイグレーションを代わりに使用できます。
キャッシュの入力
Roomデータベースが作成されたら、Apolloクエリの結果をキャッシュに書き込むことでデータを入力できます。次のコードはすべてのPostオブジェクトをローカルデータベースに保存します:
suspend fun syncAllPosts() { // Sync all pages of posts until there is no nextToken var nextToken: String? = null do { val query = GetPostsQuery(nextToken = Optional.presentIfNotNull(nextToken)) val response = apolloClient.query(query).execute() response.data?.listPosts?.items?.let { posts -> val mapped = posts.mapNotNull { it?.postDetails?.toLocalModel() } postDao.insertAll(mapped) } nextToken = response.data?.listPosts?.nextToken } while (nextToken != null)}可観測性
レスポンシブなアプリをサポートするには、データの変更を監視するローカルストアを選択してください。Roomを使用する場合、DAOを変更してKotlin Flowを返すことで、データベースの変更に対応できます。更新された監視可能なDAOは次のようになります:
@Daointerface PostDao { @Query("SELECT * FROM post") fun getAll(): Flow<List<PostEntity>>
@Query("SELECT * FROM post WHERE id = :id") fun get(id: String): Flow<PostEntity>
@Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insert(vararg posts: PostEntity)
@Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertAll(posts: List<PostEntity>)
@Delete suspend fun delete(post: PostEntity)}