gpt4 book ai didi

android - 如何取消正在运行的 LiveData 协程 block

转载 作者:行者123 更新时间:2023-12-02 18:34:14 25 4
gpt4 key购买 nike

通过使用 LiveData 的最新版本“androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha03”,我使用 LiveData 的新构建 block (LiveData + Coroutine)使用 Retrofit 执行同步网络调用,并相应地更新 ViewModel 中的不同标志(isLoading、isError)。我在“查询”LiveData 上使用 Transforamtions.switchMap,因此只要 UI 中的“查询”发生变化,“搜索产品”代码就会使用 Transformations.switchMap 开始执行。一切都工作正常,除了每当“查询”LiveData 发生更改时我想取消之前的改造调用。目前我看不到任何方法可以做到这一点。任何帮助,将不胜感激。

class ProductSearchViewModel : ViewModel() {
val completableJob = Job()
private val coroutineScope = CoroutineScope(Dispatchers.IO + completableJob)

// Query Observable Field
val query: MutableLiveData<String> = MutableLiveData()

// IsLoading Observable Field
private val _isLoading = MutableLiveData<Boolean>()
val isLoading: LiveData<Boolean> = _isLoading


val products: LiveData<List<ProductModel>> = query.switchMap { q ->
liveData(context = coroutineScope.coroutineContext) {
emit(emptyList())
_isLoading.postValue(true)
val service = MyApplication.getRetrofitService()
val response = service?.searchProducts(q)
if (response != null && response.isSuccessful && response.body() != null) {
_isLoading.postValue(false)
val body = response.body()
if (body != null && body.results != null) {
emit(body.results)
}
} else {
_isLoading.postValue(false)
}
}
}
}

最佳答案

您可以通过两种方式解决此问题:

方法#1(简单方法)

就像梅尔在他的 answer 中解释的那样,您可以在 switchMap 之外保留对作业实例的引用,并在 switchMap 中返回新的 liveData 之前取消该作业的实例。

class ProductSearchViewModel : ViewModel() {

// Job instance
private var job = Job()

val products = Transformations.switchMap(_query) {
job.cancel() // Cancel this job instance before returning liveData for new query
job = Job() // Create new one and assign to that same variable

// Pass that instance to CoroutineScope so that it can be cancelled for next query
liveData(CoroutineScope(job + Dispatchers.IO).coroutineContext) {
// Your code here
}
}

override fun onCleared() {
super.onCleared()
job.cancel()
}
}

方法#2(不太干净,但独立且可重复使用)

由于 liveData {} 构建器 block 在协程作用域内运行,因此您可以结合使用 CompletableDeffered 和协程 launch 构建器来暂停该构建器liveData block 并手动观察 query liveData 以启动网络请求作业。

class ProductSearchViewModel : ViewModel() {

private val _query = MutableLiveData<String>()

val products: LiveData<List<String>> = liveData {
var job: Job? = null // Job instance to keep reference of last job

// LiveData observer for query
val queryObserver = Observer<String> {
job?.cancel() // Cancel job before launching new coroutine
job = GlobalScope.launch {
// Your code here
}
}

// Observe query liveData here manually
_query.observeForever(queryObserver)

try {
// Create CompletableDeffered instance and call await.
// Calling await will suspend this current block
// from executing anything further from here
CompletableDeferred<Unit>().await()
} finally {
// Since we have called await on CompletableDeffered above,
// this will cause an Exception on this liveData when onDestory
// event is called on a lifeCycle . By wrapping it in
// try/finally we can use this to know when that will happen and
// cleanup to avoid any leaks.
job?.cancel()
_query.removeObserver(queryObserver)
}
}
}

您可以在 demo project 中下载并测试运行这两种方法。

编辑:更新了方法#1,在 onCleared 方法上添加作业取消,正如 yasir 在评论中指出的那样。

关于android - 如何取消正在运行的 LiveData 协程 block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57723714/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com