Android 如何取消withContext中的协同程序运行?
我有一个如下定义的存储库Android 如何取消withContext中的协同程序运行?,android,kotlin,coroutine,kotlin-coroutines,withcontext,Android,Kotlin,Coroutine,Kotlin Coroutines,Withcontext,我有一个如下定义的存储库 class StoryRepository { private val firestore = Firebase.firestore suspend fun fetchStories(): QuerySnapshot? { return try { firestore .collection("stories") .get()
class StoryRepository {
private val firestore = Firebase.firestore
suspend fun fetchStories(): QuerySnapshot? {
return try {
firestore
.collection("stories")
.get()
.await()
} catch(e: Exception) {
Log.e("StoryRepository", "Error in fetching Firestore stories: $e")
null
}
}
}
我还有一个像这样的视图模型
class HomeViewModel(
application: Application
) : AndroidViewModel(application) {
private var viewModelJob = Job()
private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
private val storyRepository = StoryRepository()
private var _stories = MutableLiveData<List<Story>>()
val stories: LiveData<List<Story>>
get() = _stories
init {
uiScope.launch {
getStories()
}
uiScope.launch {
getMetadata()
}
}
private suspend fun getStories() {
withContext(Dispatchers.IO) {
val snapshots = storyRepository.fetchStories()
// Is this correct?
if (snapshots == null) {
cancel(CancellationException("Task is null; local DB not refreshed"))
return@withContext
}
val networkStories = snapshots.toObjects(NetworkStory::class.java)
val stories = NetworkStoryContainer(networkStories).asDomainModel()
_stories.postValue(stories)
}
}
suspend fun getMetadata() {
// Does some other fetching
}
override fun onCleared() {
super.onCleared()
viewModelJob.cancel()
}
}
类HomeViewModel(
应用程序:应用程序
):AndroidViewModel(应用程序){
私有变量viewModelJob=Job()
private val uiScope=CoroutineScope(Dispatchers.Main+viewModelJob)
private val storyRepository=storyRepository()
私有var_stories=MutableLiveData()
val故事:LiveData
获取你的故事
初始化{
发射{
getStories()
}
发射{
getMetadata()
}
}
私人故事{
withContext(Dispatchers.IO){
val snapshots=storyRepository.fetchStories()
//这是正确的吗?
如果(快照==null){
cancel(CancellationException(“任务为空;本地数据库未刷新”))
return@withContext
}
val networkStories=snapshots.toObjects(NetworkStory::class.java)
val stories=NetworkStoryContainer(networkStories).asDomainModel()
_故事。postValue(故事)
}
}
挂起元数据(){
//还有其他的吸引人的事吗
}
覆盖有趣的onCleared(){
super.onCleared()
viewModelJob.cancel()
}
}
如您所见,有时,
StoryRepository().fetchStories()
可能会失败并返回null
。如果返回值为null
,则我不希望在检查snapshots
为null
块后继续执行后续操作。因此,我想取消这个特定的协同程序(运行getStories()
的一个,而不取消另一个协同程序(运行getMetadata()
)。我如何实现这一点?使用上下文从返回-ing是否是一种不好的做法?尽管您的方法是正确的,但您始终可以进行一些改进,使其更简单或更惯用(尤其是当您对自己的代码不满意时)
以下是您可能需要考虑的一些建议:
您可以使用Kotlin作用域函数,或者更具体地说是let
函数,如下所示:
private suspend fun getStories() = withContext(Dispatchers.IO) {
storyRepository.fetchStories()?.let { snapshots ->
val networkStories = snapshots.toObjects(NetworkStory::class.java)
NetworkStoryContainer(networkStories).asDomainModel()
} ?: throw CancellationException("Task is null; local DB not refreshed")
}
这样,如果null
,您将返回数据或抛出CancellationException
当您在ViewModel中使用协同路由时,如果您将此依赖项添加到gradle文件中,则可以使用协同路由
androidx.lifecycle:lifecycle-viewmodel-ktx:{version}
因此,您可以使用viewModelScope
构建将在主线程上运行的协同程序:
init {
viewModelScope.launch {
_stories.value = getStories()
}
viewModelScope.launch {
getMetadata()
}
}
您可以忘记在onCleared
期间取消其作业
,因为viewModelScope
具有生命周期意识
现在,您所要做的就是使用try catch
块或invokeOnCompletion
函数处理异常,该函数应用于launch
生成器返回的作业
。在@AnimeshSahu看来是正确的使用上下文从返回可以吗捕获取消异常的机制
?如果我想捕获取消异常
,我如何使用您的代码实现这一点?我是否要用上下文(Dispatchers.IO)包装整个
用try catch
块阻塞?@Richard如果在启动
生成器中用try catch
块包装它的调用,会更容易。或者你可以使用作业
所具有的invokeOnCompletion
函数。它的可丢弃性不会是null
,这就是你知道发生了什么的原因我明白了,它会是这样的:viewModelScope.launch{u stories.value=getStories}.invokeonpletion{cause->catch(cause:CancellationException){…}
?@Richard更像:.invokeonpletion{cause->cause?.apply{…}
。问题是,如果出现问题,原因
将不会为null
。您可以在apply
块内执行任何您想执行的操作,或者执行任何您使用的操作。我想您的意思是,如果没有任何问题,原因将是null
?您能否捕获apply
块中的异常?