amar_1995
02/11/2020, 1:04 PMjava.lang.IllegalStateException: Cannot invoke setValue on a background thread
override fun doWork(): Result {
println("Worker is Running >>>> ")
val database = DatabaseClient.getInstance(applicationContext)
val server = APIClient.retrofitServiceProvider<ArticleService>()
val articleRepo = ArticleRepo.getInstance(database, server, applicationContext)
GlobalScope.launch {
articleRepo.clearData()
val data = articleRepo.refreshData(1)
}
return Result.success()
}
Here, I am trying to clean database and then again making a server call which will fetch data from server and load it into local database.amar_1995
02/11/2020, 1:05 PMclearData
is a suspend function which will clear a local dbsatyan
02/11/2020, 1:07 PMFrancisco Javier Ruiz Rodriguez
02/11/2020, 1:08 PMclearData
has a flow/livedata which is trying to update the UI in a non-main threadamar_1995
02/11/2020, 1:21 PMclearData
is suspend function declare in room dao to clear databaseamar_1995
02/11/2020, 1:22 PMabstract class NetworkBoundResource<ResultType, RequestType>
@MainThread constructor(private val appExecutors: AppExecutors) {
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()
// we re-attach dbSource as a new source, it will dispatch its latest value quickly
result.addSource(dbSource) { newData ->
setValue(Resource.loading(newData))
}
result.addSource(apiResponse) { response ->
result.removeSource(apiResponse)
result.removeSource(dbSource)
when (response) {
is ApiSuccessResponse -> {
appExecutors.diskIO().execute {
saveCallResult(processResponse(response))
appExecutors.mainThread().execute {
// we specially request a new live data,
// otherwise we will get immediately last cached value,
// which may not be updated with latest results received from network.
result.addSource(loadFromDb()) { newData ->
setValue(Resource.success(newData))
}
}
}
}
is ApiEmptyResponse -> {
appExecutors.mainThread().execute {
// reload from disk whatever we had
result.addSource(loadFromDb()) { newData ->
setValue(Resource.success(newData))
}
}
}
is ApiErrorResponse -> {
onFetchFailed()
result.addSource(dbSource) { newData ->
setValue(Resource.error(response.errorMessage, newData))
}
}
}
}
}
protected open fun onFetchFailed() {}
fun asLiveData() = result as LiveData<Resource<ResultType>>
@WorkerThread
protected open fun processResponse(response: ApiSuccessResponse<RequestType>) = response.body
@WorkerThread
protected abstract fun saveCallResult(item: RequestType)
@MainThread
protected abstract fun shouldFetch(data: ResultType?): Boolean
@MainThread
protected abstract fun loadFromDb(): LiveData<ResultType>
@MainThread
protected abstract fun createCall(): LiveData<ApiResponse<RequestType>>
}
satyan
02/11/2020, 1:22 PMamar_1995
02/11/2020, 1:22 PMamar_1995
02/11/2020, 1:23 PMrefreshData
is implementation of above abstract classAnastasia Finogenova
02/11/2020, 2:29 PMAnastasia Finogenova
02/11/2020, 2:31 PMAnastasia Finogenova
02/11/2020, 2:31 PMamar_1995
02/11/2020, 3:18 PM