NetworkBoundResourceとKotlinコルーチンでリポジトリパターンを実装する方法について何かアイデアはありますか?GlobalScopeを使用してコルーチンを起動できることはわかっていますが、コルーチンのリークにつながる可能性があります。viewModelScopeをパラメーターとして渡したいのですが、実装に関しては少しトリッキーです(私のリポジトリはViewModelのCoroutineScopeを知らないためです)。
abstract class NetworkBoundResource<ResultType, RequestType>
@MainThread constructor(
private val coroutineScope: CoroutineScope
) {
private val result = MediatorLiveData<Resource<ResultType>>()
init {
result.value = Resource.loading(null)
@Suppress("LeakingThis")
val dbSource = loadFromDb()
result.addSource(dbSource) { data ->
result.removeSource(dbSource)
if (shouldFetch(data)) {
fetchFromNetwork(dbSource)
} else {
result.addSource(dbSource) { newData ->
setValue(Resource.success(newData))
}
}
}
}
@MainThread
private fun setValue(newValue: Resource<ResultType>) {
if (result.value != newValue) {
result.value = newValue
}
}
private fun fetchFromNetwork(dbSource: LiveData<ResultType>) {
val apiResponse = createCall()
result.addSource(dbSource) { newData ->
setValue(Resource.loading(newData))
}
result.addSource(apiResponse) { response ->
result.removeSource(apiResponse)
result.removeSource(dbSource)
when (response) {
is ApiSuccessResponse -> {
coroutineScope.launch(Dispatchers.IO) {
saveCallResult(processResponse(response))
withContext(Dispatchers.Main) {
result.addSource(loadFromDb()) { newData ->
setValue(Resource.success(newData))
}
}
}
}
is ApiEmptyResponse -> {
coroutineScope.launch(Dispatchers.Main) {
result.addSource(loadFromDb()) { newData ->
setValue(Resource.success(newData))
}
}
}
is ApiErrorResponse -> {
onFetchFailed()
result.addSource(dbSource) { newData ->
setValue(Resource.error(response.errorMessage, newData))
}
}
}
}
}
}
NetworkBoundResource
。私のコメントはより一般的です:私見、Kotlinリポジトリ実装はコルーチン関連のAPIを公開する必要があります。
LiveData
RxJavaまたはKotlinコルーチンのいずれかの能力が不足しています。LiveData
アクティビティまたはフラグメントへの「ラストマイル」の通信に非常に適しており、それを考慮して設計されています。あなたがリポジトリをスキップし、ちょうど持っているしたい場合や、小さなアプリケーションのために、ViewModel
と話をまっすぐにRoomDatabase
、LiveData
罰金です。
suspend
関数またはreturnChannel
/Flow
オブジェクトを公開する必要があります。次に、実際のコルーチンがビューモデルに設定されます。LiveData
リポジトリではなく、ビューモデルによって導入されます。