Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package me.alhaz.tutorial.architecturecomponent.helper
- import androidx.annotation.MainThread
- import androidx.annotation.WorkerThread
- import androidx.lifecycle.LiveData
- import androidx.lifecycle.MediatorLiveData
- import me.alhaz.tutorial.architecturecomponent.helper.valueobject.ApiResponse
- import me.alhaz.tutorial.architecturecomponent.helper.valueobject.Resource
- import me.alhaz.tutorial.architecturecomponent.helper.valueobject.Status.SUCCESS
- import me.alhaz.tutorial.architecturecomponent.helper.valueobject.Status.ERROR
- import me.alhaz.tutorial.architecturecomponent.helper.valueobject.Status.EMPTY
- abstract class NetworkBoundResource<ResultType, RequestType>
- @MainThread constructor(private val appExecutor: AppExecutors){
- private val result = MediatorLiveData<Resource<ResultType>>()
- init {
- result.value = Resource.empty(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: LiveData<ApiResponse<RequestType>> = createCall()
- // we re-attach dbSource as a new source, it will dispatch its latest value quickly
- result.addSource(dbSource) { newData ->
- setValue(Resource.empty(newData))
- }
- result.addSource(apiResponse) { response ->
- result.removeSource(apiResponse)
- result.removeSource(dbSource)
- when (response.status) {
- EMPTY -> {
- appExecutor.mainThread().execute {
- result.addSource(loadFromDb()) { newData ->
- setValue(Resource.success(newData))
- }
- }
- }
- SUCCESS -> {
- appExecutor.diskIO().execute {
- saveCallResult(response.body)
- appExecutor.mainThread().execute {
- result.addSource(loadFromDb()) { newData ->
- setValue(Resource.success(newData))
- }
- }
- }
- }
- EMPTY -> {
- appExecutor.mainThread().execute {
- result.addSource(loadFromDb()) { newData ->
- setValue(Resource.success(newData))
- }
- }
- }
- ERROR -> {
- onFetchFailed()
- result.addSource(dbSource) { newData ->
- setValue(Resource.error(response.message, newData))
- }
- }
- }
- }
- }
- protected open fun onFetchFailed() {}
- fun asLiveData() = result as LiveData<Resource<ResultType>>
- @MainThread
- protected abstract fun loadFromDb(): LiveData<ResultType>
- @MainThread
- protected abstract fun shouldFetch(data: ResultType?): Boolean
- @MainThread
- protected abstract fun createCall(): LiveData<ApiResponse<RequestType>>
- @WorkerThread
- protected abstract fun saveCallResult(item: RequestType)
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement