首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在Kotlin 1.3中更新协程中的UI

如何在Kotlin 1.3中更新协程中的UI
EN

Stack Overflow用户
提问于 2018-10-31 16:34:16
回答 3查看 22.1K关注 0票数 33

我正在尝试调用API,当我的变量准备就绪时,分别更新UI组件。

这是我的网络单例,他正在启动协程:

代码语言:javascript
运行
复制
object MapNetwork {
    fun getRoute(request: RoutesRequest,
                 success: ((response: RoutesResponse) -> Unit)?,
                 fail: ((throwable: Throwable) -> Unit)? = null) {
        val call = ApiClient.getInterface().getRoute(request.getURL())

        GlobalScope.launch(Dispatchers.Default, CoroutineStart.DEFAULT, null, {

            try {
                success?.invoke(call.await())
            } catch (t: Throwable) {
                fail?.invoke(t)
            }

        })
    }
}

我是这样称呼它的:

代码语言:javascript
运行
复制
network.getRoute(request,
            success = {
                // Make Some UI updates
            },
            fail = {
                // handle the exception
            }) 

我得到了一个异常,说不能从UI线程以外的任何线程更新UI:

代码语言:javascript
运行
复制
com.google.maps.api.android.lib6.common.apiexception.c: Not on the main thread

我已经尝试过this解决方案,但是从Kotlin1.3开始,Continuation<T>类中的resume就被“弃用”了

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-11-05 21:15:45

要回答您直接提出的问题,您只需在正确的上下文中启动协程:

代码语言:javascript
运行
复制
val call = ApiClient.getInterface().getRoute(request.getURL())
GlobalScope.launch(Dispatchers.Main) {
    try {
        success?.invoke(call.await())
    } catch (t: Throwable) {
        fail?.invoke(t)
    }
}

然而,这只是冰山一角,因为您的方法使用协程的方式是错误的。它们的主要好处是避免了回调,但您正在重新引入它们。您使用的GlobalScope也侵犯了的最佳实践,因为它不是用于生产的。

显然,您已经有了一个异步API,它为您提供了一个可以awaitDeferred<RoutesResponse>。使用方法如下:

代码语言:javascript
运行
复制
scope.launch {
    val resp = ApiClient.getInterface().getRoute(request.getURL()).await()
    updateGui(resp)
}

你可能会因为我建议在你必须执行可挂起代码的每个图形用户界面回调中都有一个launch块而苦恼,但这实际上是使用这个特性的推荐方式。它与编写Thread { ... my code ... }.start()是严格并行的,因为您的launch块的内容将与外部的代码并发运行。

上面的语法假设您有一个实现CoroutineScopescope变量。例如,它可以是您的Activity

代码语言:javascript
运行
复制
class MyActivity : AppCompatActivity(), CoroutineScope by MainScope {

    override fun onDestroy() {
        super.onDestroy()
        cancel()
    }
}

MainScope委托将默认协程调度程序设置为Dispatchers.Main。这允许您使用普通的launch { ... }语法。

票数 29
EN

Stack Overflow用户

发布于 2020-03-24 23:41:31

代码语言:javascript
运行
复制
private var viewModelJob = Job()
private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)

uiScope.launch {
            withContext(Dispatchers.IO) {
                //Do background tasks...
                withContext(Dispatchers.Main){
                    //Update UI
                }
            }
        }
票数 17
EN

Stack Overflow用户

发布于 2018-10-31 16:47:02

如果你使用的是协程-android,你可以使用Dispatchers.Main

(gradle依赖项为implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0")

代码语言:javascript
运行
复制
network.getRoute(request,
        success = {
            withContext(Dispatchers.Main) {
                // update UI here
            }
        },
        fail = {
            // handle the exception
        }) 
票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53079234

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档