【问题标题】:When and how to call suspend function from Android Activity?何时以及如何从 Android Activity 调用挂起函数?
【发布时间】:2019-07-06 09:23:51
【问题描述】:

我有一个 suspend 函数调用 POST 请求到服务器。我想在活动中配置一些文本来显示我从服务器收到的信息。

suspend fun retrieveInfo():String 

我尝试在 onCreateonResume 内部调用,但运行时崩溃。

runBlocking { 
    retrieveInfo()
}
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.google.augmentedimage/com.google.AugmentedImageActivity}: android.os.NetworkOnMainThreadException
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3086)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3229)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)

我应该将这些挂起调用放在哪里(在活动生命周期的哪一部分)?我应该使用runBlocking 以外的东西吗?

【问题讨论】:

  • 从你的主线程启动一个协程。 CoroutineScope(Dispatchers.Main).launch { withContext(Dispatchers.IO) { myFun() }
  • 一般来说,此类事情的首选方法是使用ViewModel,然后使用它内置在viewModelScopemedium.com/androiddevelopers/… 中的更多详细信息)

标签: android kotlin kotlin-coroutines


【解决方案1】:

默认情况下,runBlocking 在调用线程runBlocking 中运行暂停代码block

因此,如果您从Activity 回调中调用runBlocking,您的挂起块将在主线程上执行,您无法从主线程访问网络(查询服务器)。

您需要在协程块中为该调用切换调度程序。最简单的代码修复方法是将执行移至Dispatchers.IO

runBlocking {
    withContext(Dispatchers.IO) {
        retrieveInfo()
    }
}

话虽如此,我建议两件事(与您的问题没有直接关系):

  1. 阅读Coroutines on Android(本部分及以下部分)

2。不要在你的情况下使用runBlocking,而是定义一个正确的job并使用job.launch{}

【讨论】:

  • 您的runBlockingIO 上下文的快速解决方案允许代码运行。但是,除非 API 调用足够快,否则还是会给出Unable to start activity ComponentInfojava.net.SocketTimeoutException
  • @user3087615 这完全是另一个与协程本身无关的问题。您需要对您的 api 调用进行适当的错误处理。
  • @user3087615 你真的应该遵循我回答的第二点,因为在 Activity 生命周期方法中调用 runBlocking 是一个非常糟糕的主意。
  • 有没有关于如何创建工作和启动的好文档?我是 kotlin 的新手,正在努力寻找好的文档。如果您可以展示一个简短的示例或指向文档,那就太棒了。
  • 不是真的,请提供一个更好的:(
【解决方案2】:

如果你想写在activity中:

class MyActivity : AppCompatActivity() {
private val scope = CoroutineScope(newSingleThreadContext("name"))

fun doSomething() {
    scope.launch { ... }
  }
}

【讨论】:

  • newSingleThreadContext 已过时。
猜你喜欢
  • 2021-11-24
  • 2020-04-13
  • 2021-12-21
  • 1970-01-01
  • 2018-11-10
  • 1970-01-01
  • 2021-07-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多