我正在使用 Kotlin for Android 构建一个简单的演示应用程序,它使用 Jsoup 检索网页的标题。我正在使用 Dispatchers.Main 作为上下文进行网络调用。
我对协程的理解是,如果我在 Dispatchers.Main 上调用 launch,它会在主线程上运行,但会暂停执行以免阻塞线程。
我对android.os.NetworkOnMainThreadException的理解是因为网络操作繁重,在主线程上运行会阻塞。
所以我的问题是,如果协程不会阻塞运行它的线程,NetworkOnMainThreadException 真的有效吗?以下是在 Jsoup.connect(url).get() 处抛出给定异常的一些示例代码:
class MainActivity : AppCompatActivity() {
val job = Job()
val mainScope = CoroutineScope(Dispatchers.Main + job)
// called from onCreate()
private fun printTitle() {
mainScope.launch {
val url ="https://kotlinlang.org"
val document = Jsoup.connect(url).get()
Log.d("MainActivity", document.title())
// ... update UI with title
}
}
}
我知道我可以简单地使用 Dispatchers.IO 上下文运行它并将此结果提供给主/UI 线程,但这似乎避开了协程的一些实用程序。
作为引用,我使用的是 Kotlin 1.3。
最佳答案
My understanding of coroutines is that if I call launch on the Dispatchers.Main it does run on the main thread, but suspends the execution so as to not block the thread.
为了不阻塞线程而暂停执行的唯一点是标记为 suspend 的方法 - 即,暂停方法。
由于 Jsoup.connect(url).get() 不是挂起方法,它会阻塞当前线程。当您使用 Dispatchers.Main 时,当前线程是主线程,您的网络操作直接在主线程上运行,导致 NetworkOnMainThreadException。
像 get() 方法这样的阻塞工作可以通过将其包装在 withContext() 中来暂停,是一个暂停方法并且确保 Dispatchers.Main 在方法运行时不会被阻塞。
mainScope.launch {
val url ="https://kotlinlang.org"
val document = withContext(Dispatchers.IO) {
Jsoup.connect(url).get()
}
Log.d("MainActivity", document.title())
// ... update UI with title
}
关于android - NetworkOnMainThreadException 是否对协程中的网络调用有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53582860/