Jon*_*gat 18 multithreading android coroutine android-architecture-components
在我学习协程以及如何在 android 应用程序中正确使用它们时,我发现了一些令我感到惊讶的事情。
在启动viewModelScope.launch { }lambda 中使用并设置断点启动协程时,我注意到我的应用程序不再响应,因为它仍在主线程上。
这让我感到困惑,因为文档viewModelScope.launch { }明确指出:
在不阻塞当前线程的情况下启动一个新的协程
当前线程不是主线程吗?如果默认情况下它不在不同的线程上运行,那么启动的全部目的是什么?
我能够viewModelScope.launch(Dispatchers.IO){ }在另一个线程上使用它按我的预期工作,即在另一个线程上运行它。
我试图通过该launch方法完成的是调用存储库并执行一些 IO 工作,即调用 Web 服务并将数据存储在房间数据库中。所以我想调用viewModelScope.launch(Dispatchers.IO){ }在不同的线程上完成所有工作,最后更新 LiveData 结果。
viewModelScope.launch(Dispatchers.IO){
liveData.postValue(someRepository.someWork())
}
所以我的第二个问题是,这是要走的路吗?
ngo*_*goa 12
ViewModelScope.launch { } 在主线程上运行,但也为您提供了运行其他调度程序的选项,因此您可以同步运行 UI 和后台操作。
以你为例:
fun thisWillRunOnMainThread() {
viewModelScope.launch {
//below code will run on UI thread.
showLoadingOnUI()
//using withContext() you can run a block of code on different dispatcher
val result = novel.id = withContext(Dispatchers.IO) {
withsomeRepository.someWork()
}
//The below code waits until the above block is executed and the result is set.
liveData.value = result
finishLoadingOnUI()
}
}
Run Code Online (Sandbox Code Playgroud)
为了获得更多参考,我想说有一些简洁的文章可以帮助您理解这个概念。
所以我的第二个问题是,这是要走的路吗?
我希望您目前的方法有两件事会有所不同。
1.) 第一步是通过 定义后台操作的调度程序withContext。
class SomeRepository {
suspend fun doWork(): SomeResult = withContext(Dispatchers.IO) {
...
}
}
Run Code Online (Sandbox Code Playgroud)
这样,操作本身在后台线程上运行,但您没有强制您的原始范围为“线程外”。
2.) Jetpack Lifecycle KTX 提供了liveData {协程构建器,因此您不必postValue手动进行。
val liveData: LiveData<SomeResult> = liveData {
emit(someRepository.someWork())
}
Run Code Online (Sandbox Code Playgroud)
现在你甚至不用到后顾之忧viewModelScope和launch等。
默认主线程背后的想法是您可以运行 UI 操作而无需更改上下文。我猜这是 Kotlin 协程库作者选择的约定
假设默认情况下启动在 IO 线程上运行,那么代码将如下所示
viewmodelScope.launch {
val response = networkRequest()
withContext(Dispatchers.Main) {
renderUI(response)
}
}
Run Code Online (Sandbox Code Playgroud)
假设如果默认情况下启动在默认线程上运行,那么代码将如下所示
viewmodelScope.launch {
val response: Response = null
withContext(Dispatchers.IO) {
response = networkRequest()
}
withContext(Dispatchers.Main) {
renderUI(response)
}
}
Run Code Online (Sandbox Code Playgroud)
由于默认启动是在主线程上,所以现在您必须执行以下操作
viewmodelScope.launch {
val response: Response = null
withContext(Dispatchers.IO) {
response = networkRequest()
}
renderUI(response)
}
Run Code Online (Sandbox Code Playgroud)
为了避免使用 null 初始化响应的混乱代码,我们还可以将 networkRequest 设为挂起,并将 networkRequest() 函数的业务逻辑包装在 withContext(Dispatchers.IO) 中,这也是很多人编写 networkRequest() 函数的方式!希望这是有道理的
| 归档时间: |
|
| 查看次数: |
3502 次 |
| 最近记录: |