我正在使用翻新,LiveData,会议室(Android AAC)。 NetworkBoundResource
是整合googlesimple提供的网络资源和空间的绝佳帮手。
由于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
的核心作用。
任何想法都会受到赞赏。
答案 0 :(得分:1)
我也有同样的问题,我的解决方法是这样。我建议您不要使用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
}
答案 1 :(得分:0)
无需向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()
}