11
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

MVVM + Repository + Hilt + Retrofitで、Repositoryレイヤーからキャッシュを用いてAPIデータを取得する

Posted at

はじめに

先日Retrofitを、使ってデータを取得する処理を書いている時に、毎回毎回リモートサーバーからデータを取得するのは、通信量での負担がかかってしまいパフォーマンスが落ちてしまうという、レビューを受けてそれを解消するために、Repositoryレイヤーをうまく使って通信量の負担を減らす処理を教えていただいたので記録がてら書いておきます。

やり方

@Singleton
class MainRepository @Inject constructor(private val service: MainService) {
    private var cache: List<Demo>? = null
    
    suspend fun fetchDemo() = service.fetchDemo().body().also {
        cache = it
    }
    suspend fun getDemo() = cache ?: fetchDemo()
}

イメージとしては、getDemo()を呼び出して、その時にcachenullならばfetchDemo()を呼び出して、cacheが値を持っているならばそのまま返すという感じです。これにより、呼び出す時にはcacheからなのかfetchDemo()からなのかこちらは意識せずに、データを取得することができます。

もしリモートサーバーから最新の情報を取得する必要がある場合だけfetchDemo()を呼び出してあげればOKですね!

同時呼び出しへの対策

上記の方法を使えば、毎回毎回リモートから取得する必要がなくなるので、だいぶ負担が減ると思います。
おまけで、2回以上同時に関数を呼ばれた際の対処法も載せておきます。

@Singleton
class MainRepository @Inject constructor(private val service: MainService) {
    private var cache: List<Demo>? = null
    private val mutex = Mutex()
    
    suspend fun fetchDemo() = service.fetchDemo().body().also {
        cache = it
    }
    suspend fun getDemo() {
        mutex.withLock {
            cache ?: fetchDemo()
        }
    }
}

Mutexを使うことで、ブロック内を同時に一件のみ実行するようにすることができ、しっかり対策できました!

終わりに

少しづつでも、こういった細かいところまでしっかりコードが書けるようになりたいと思いました🧐
まだまだ自分のコードは改善できるところがたくさんあるはずなので、ちゃんと勉強していきます。

11
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?