日々是好日

プログラミングについてのあれこれ、ムダ知識など

FireStoreとローカルDBからのデータ取得についてメモ

FireStoreとローカルDBとのデータ取得・同期について、なんとなく動いた()のでメモ。

なお、リモートのデータソースはFireStoreを利用、ローカルはRoomで実装している。

リモートデータソースからの結果待ちの間、ローカルで保持しているデータを表示しておこうというよくあるシチュ。

処理フローはこんな感じ。 常にリモートに同期させるならこれでいいけど、ローカルの更新をリモートに反映させたときの処理がうまくいかない気がする。 全然わからん。

MainActViewModel
↓
UseCase(実装はUseCaseInteractor)
↓
Repository
↓
リモート/ローカルデータソースに並列に問合せ
(当然ローカルの方が先に返る)
↓
ローカルデータをいったん返す
↓
リモートデータが取得され次第、コールバックで値を返す

処理の起点となるViewModel。 getFests()をコールすることでデータ取得を開始する。

class MainActViewModel(val app: Application) : AndroidViewModel(app) {

  // RecyclerView のリストにバインド
  private val _festListLiveData = MutableLiveData<List<Fest>>()
  val festListLiveData: LiveData<List<Fest>>
  get() = _festListLiveData

  private val useCase: FestControlUseCase =
    FestControlInteractor( /*Repositoryを渡す*/ )

  fun getFests() {
    viewModelScope.launch(Dispatchers.IO) {
      
      // Coroutineの起動
      launch {
        // リモートデータソースとローカルデータソース両方からデータを取得
        val fests = useCase.getFests(object : RemoteDataSourceCallback<Fest> {
          
          // リモートデータソースからデータを受信した際のコールバック
          override fun onResult(contents: List<Fest>) {
            _festListLiveData.postValue(contents)
          }
        })

        // 先にローカルデータソースからfestsに値が返るのでpostする
        _festListLiveData.postValue(fests)
      }
    }
  }
}

データソースを集約しているRepository。 非同期処理が必要なのでCoroutineScopeを実装。

// Repositoryパターンを採用してみた
class AppRepository(
  private val firebaseRemoteDataSource: FirebaseRemoteDataSource,
  private val appLocalDataSource: AppLocalDataSource
) : AppDataSource, CoroutineScope {

  // FestControlUseCase#getFestsから流れてくる
  override suspend fun findAllFests(listener: RemoteDataSourceCallback<Fest>): List<Fest> {
    
    // Coroutineの起動
    launch {
      // リモートデータソースからのデータ取得。
      // 実装で store.collection("fests").get().await() をしているので、
      // 基本的に時間がかかる処理。
      val remoteFests = firebaseRemoteDataSource.findAllFests(listener)
      
      //データが取得できたらローカルを更新
      if (!remoteFests.isNullOrEmpty()) {
        appLocalDataSource.deleteAllFests()
        appLocalDataSource.insertFests(remoteFests)

        // リモートのデータをコールバック
        listener.onResult(remoteFests)
      }
    }

    // リモートデータソースからの取得中にローカルデータソースからデータを返す
    // ここは上で起動したCoroutineの外
    return appLocalDataSource.findAllFests(listener)
  }
}

どう書けばいいのかぜんぜんわからない……。