问题
So I am migrating an example app from RxJava to Kotlin/Anko Corountines and I am wondering if I am doing the best (first) approach of it:
fun getPopulationList() {
val ref = asReference()
async(UI) {
try {
ref().setCurrentState(ViewState.State.LOADING)
val background = bg {
repository.populationResponse().execute().body()
}
ref().let {
it.response = background.await()
it.mvpView?.onGetData(it.response)
it.setCurrentState(ViewState.State.FINISH)
}
} catch (e: Exception) {
e.printStackTrace()
ref().mvpView?.onError(e)
}
}
}
I am using an MVP architecture where my Presenter
base class had a CompositeSubscription
and in the onDestroy
's fragment or activity method simple unsubscribe and clear the CompositeSubscription
object. But i am wondering if the asReference()
function from Anko Coroutines does the same and there is no need to save a list of Deferred<T>
and then iterate it and cancel one by one.
BTW if I add a Thread.sleep(5000)
to simulate a big transaction and destroy the Fragment I can see in the logcat the HTTP response even after the fragment is not visible/destroyed while with RxJava doesn't happen, so I think I am not using properly.
UPDATE
fun getPopulationList() {
val ref = asReference()
job = launch(UI) {
try {
ref().setCurrentState(ViewState.LOADING)
val background = bg {
Thread.sleep(5000) //simulate heavy IO
if (isActive) {
repository.populationResponse().execute().body()
} else {
return@bg null
}
}
ref().let {
it.response = background.await()
it.mvpView?.onGetData(it.response)
it.setCurrentState(ViewState.FINISH)
}
} catch (e: Exception) {
RestHttpExceptionHandler().handle(UI, e, ref())
}
}
}
I am able to cancel the coroutine while calling job.cancel()
in onDestroy()
method but to make it work I have to check if the job is active or not and that translate into an if/else and a return or not data. Is there any better way to return something when the job was cancelled?
回答1:
As you can see in asReference() source it is nothing other than a weak reference and invoke method to get reference that throws CancellationException
when object is collected. it does not do anything to cancel operation. just is aware of collected object.
so you need to keep reference of a Job or subtype of it to cancel operation.
launch
coroutine builder from kotlinx.coroutines returns a Job instance. here is an example:
private lateinit var job: Job
private fun startCoroutines() {
val ref = asReference()
job = launch(UI) {
try {
val deferred = async(parent = coroutineContext[Job]) {
//do some work
result//return
}
ref().setData(deferred.await())
} catch (e: Exception) {
e.printStackTrace()
}
}
}
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
Notes:
1- when result type is not important launch
can be used instead of async
.
2- to do cancellation in child coroutines you must create parent/child job hierarchies. I passed parent(launch
) Job
reference to child coroutine(async) to achieve this.
3- as cancellation is cooperative cancellation implementation must be done in async(see examples here).
3- job.cancel()
is used in onDestroy cancels job and it's child async. this can be done in Presenter in MVP pattern.
来源:https://stackoverflow.com/questions/47461766/what-is-the-correct-way-of-using-anko-coroutines-extensions