はじめに
先日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()
を呼び出して、その時にcache
がnull
ならば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
を使うことで、ブロック内を同時に一件のみ実行するようにすることができ、しっかり対策できました!
終わりに
少しづつでも、こういった細かいところまでしっかりコードが書けるようになりたいと思いました🧐
まだまだ自分のコードは改善できるところがたくさんあるはずなので、ちゃんと勉強していきます。