【问题标题】:How to use NetworkBoundResource with suspend fun in Retorfit如何在 Retrofit 中使用具有暂停乐趣的 NetworkBoundResource
【发布时间】:2019-11-22 00:27:47
【问题描述】:

我正在使用 Retrofit、LiveData、Room (Android AAC)。 NetworkBoundResourcegooglesimple提供的网络源和房间结合的好帮手。

由于 Retrofit 2.6.0 引入了对挂起的内置支持,我尝试修改 NetworkBoundResource 以使用挂起功能代替 LiveDataCallAdapter,但遇到了很多麻烦。

这是我的修改:

abstract class NetworkBondResource<ResultType, RequestType>
@MainThread constructor() {
    private val result = MediatorLiveData<Resource<ResultType>>()

    private val supervisorJob = SupervisorJob()

    init {
        result.value = Resource.loading(null)
    }

    fun asLiveData() = result as LiveData<Resource<ResultType>>

    suspend fun load() {
        withContext(Dispatchers.Main) {
            val dbSource = loadFromDb()
            result.addSource(dbSource) { data ->
                result.removeSource(dbSource)
                if (shouldFetch(data)) {
                    // ! HERE--------------
                    GlobalScope.launch(Dispatchers.IO) {
                        fetchFromNetwork(dbSource)
                    }
                } else {
                    result.addSource(dbSource) { newData ->
                        setValue(Resource.success(newData))
                    }
                }
            }
        }
    }

    // others code...
}

问题是result.addSource(dbSource) 内的代码无法继承外部作用域。我必须使用GlobalScope 来启动一个新的协程,这将导致“协程泄漏”,因为它不受viewModel 范围的控制。

我还找到了another way。但是这个方案违背了single trusted source的原则,失去了NetworkBoundResource的核心作用。

任何想法都会受到赞赏。

【问题讨论】:

  • 我也遇到了同样的情况,正在寻找解决方案,也许你可以试试看这个link

标签: android retrofit2 android-livedata kotlin-coroutines


【解决方案1】:

无需向 NetworkBoundResource 本身添加协程功能。

您可以在覆盖函数时调用协程,如下所示:

fun getList(
    coroutineScope: CoroutineScope
): LiveData<Resource<List<Content>>> {
    return object : NetworkBoundResource<List<Content>, List<Content>>(coroutineScope) {
        override fun onFetchFailed() {
            super.onFetchFailed()
        }

        override fun saveCallResult(items: List<Content>) {
            coroutineScope.launch {
                contentDao.addList(items)
            }
        }

        override fun shouldFetch(data: List<Content>?): Boolean {
            return true
        }

        override fun loadFromDb(): LiveData<List<Content>> {
                contentDao.loadSportContents(sport)
        }

        override fun createCall(): LiveData<Resource<List<Content>>> {
            return pullSportContentFromServer(coroutineScope)
        }
    }.asLiveData()
}

【讨论】:

    【解决方案2】:

    我也遇到了同样的问题,我的解决方法是这样的。我建议您不要使用 GlobalScope for these reasons。明确 result.addSoruce 只能在主线程中声明。希望对您有所帮助,如果有更好的解决方案请告诉我。

     private val result = MediatorLiveData<Resource<ResultType>>()
    private val supervisorJob = SupervisorJob()
    
    suspend fun load(): NetworkBoundResource<ResultType, RequestType> {
    
        val context = Dispatchers.IO
        context + supervisorJob
    
    
        withContext(Dispatchers.Main) {
                result.value = Resource.loading(null)
                val dbResult = loadFromDb()
                result.addSource(dbResult){data->
                    result.removeSource(dbResult)
                    if (shouldFetch(data)){
                       try {
                           CoroutineScope(context).launch {
                               fetchFromNetwork(dbResult)
                           }
                       }catch (e:Exception){
                           Timber.i("NetworkBoundResource: An error happened: $e")
                           result.addSource(dbResult){newData->
                               setValue(Resource.error(e.message!!, newData))
                           }
                       }
                    }else{
                        Timber.i("NetworkBoundResource: Return data from local database")
                        result.addSource(dbResult){newData->
                            setValue(Resource.success(newData))
                        }
    
                    }
                }
    
        }
    
        return this
    
    }
    

    【讨论】:

      猜你喜欢
      • 2020-04-05
      • 2020-01-04
      • 1970-01-01
      • 2022-07-25
      • 2019-05-20
      • 2020-06-24
      • 2018-08-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多