我刚刚开始学习kotlin coroutines,并试图模拟一些长时间的api-calls,并在UI上显示结果:
class MainActivity : AppCompatActivity() {
fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
override
fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
this.setContentView(R.layout.activity_main)
val resultTV = findViewById(R.id.text) as TextView
val a = async(CommonPool) {
delay(1_000L)
6
}
val b = async(CommonPool) {
delay(1_000L)
7
}
launch(< NEED UI thread here >) {
val aVal = a.await()
val bVal = b.await()
resultTV.setText((aVal * bVal).toString())
}
}
}
我不明白如何将launch
方法与main
上下文使用。
不幸的是,我找不到有关在Coroutines官方教程中提供某些特定线程的结果的任何内容。
edit :
还请参见Kotlin Repo
中的官方示例您需要实现连续界面,该接口将呼叫到Android UI线程和Coroutine Context
例如。(从这里)
private class AndroidContinuation<T>(val cont: Continuation<T>) : Continuation<T> by cont {
override fun resume(value: T) {
if (Looper.myLooper() == Looper.getMainLooper()) cont.resume(value)
else Handler(Looper.getMainLooper()).post { cont.resume(value) }
}
override fun resumeWithException(exception: Throwable) {
if (Looper.myLooper() == Looper.getMainLooper()) cont.resumeWithException(exception)
else Handler(Looper.getMainLooper()).post { cont.resumeWithException(exception) }
}
}
object Android : AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> =
AndroidContinuation(continuation)
}
然后尝试:
launch(Android) {
val aVal = a.await()
val bVal = b.await()
resultTV.setText((aVal * bVal).toString())
}
更多信息:
https://medium.com/@macastiblancot/android-coroutines-coroutines-getting-rid-of-runonuithreadhread-and-callbacks-callbacks-cleaner-threaner-threadhardling-and-more-234c0a9bd8eb#.r2buf5e6h
您应在kotlinx.coroutines项目的kotlinx-coroutines-android
模块中用UI
上下文中的< NEED UI thread here >
替换CC_3。它的用法在UI编程指南中用Coroutines进行了解释。
首先包括为Android设计的正确库
build.gradle
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android{
...
dependencies{
...
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.19.3"
}
kotlin {
experimental {
coroutines "enable"
}
}
}
然后您可以自由使用 ui
suspend private fun getFilteredGList(enumList: List<EnumXXX>) = mList.filter {
...
}
private fun filter() {
val enumList = listOf(EnumX1, EnumX2)
launch(UI){
val filteredList = getFilteredList(enumList)
setMarkersOnMap(filteredList)
}
}
对于那些使用 kotlin实验在中使用 kotlin实验的人 。
kotlin {
experimental {
coroutines "enable"
}
}
有几个有用的工具可以用于在Activity
/Fragment
中长时间运行API呼叫的目的。因此,基本上,如果您想并行运行两个长期运行的任务,并且两者都完成后更新UI,则可以下一步进行:
lifecycleScope.launch {
// launching two tasks in parallel
val aValDeferred = executeLongRunningTask1Async()
val bValDeferred = executeLongRunningTask2Async()
// wait for both of them are finished
val aVal = aValDeferred.await()
val bVal = bValDeferred.await()
// update UI
resultTV.setText((aVal * bVal).toString())
}
private fun executeLongRunningTask1Async(): Deferred<Int> = lifecycleScope.async(Dispatchers.Default) {
delay(1_000L)
6
}
private fun executeLongRunningTask2Async(): Deferred<Int> = lifecycleScope.async(Dispatchers.Default) {
delay(1_000L)
7
}
lifecycleScope
-是CoroutineScope
,默认情况下它具有Dispatchers.Main
上下文,这意味着我们可以在launch
块中更新UI。对于LifecycleScope
,使用androidx.lifecycle:lifecycle-runtime-ktx:2.4.0
或更高。
lifecycleScope.async(Dispatchers.Default)
-此处Dispatchers.Default
用作Coroutine的上下文,使async
块在背景线程中运行。
anko有一个包装器可以非常简单 - 请参阅:https://github.com/kotlin/anko/wiki/anko-coroutines
private fun doCallAsync() = async(UI) {
val user = bg { getUser() }
val name = user.await().name
val nameView = findViewById(R.id.name) as TextView
nameView.text = name;
}
此答案可能是OP问题之后的2.5岁,但在类似情况下仍可能会帮助其他人。
最初的目标可以比上面接受的答案要简单得多,而无需使用异步/等待(语句1、2和3,将按照预期执行其相关延迟):
override fun onCreate(savedInstanceState: Bundle?) {
:
:
:
:
GlobalScope.launch(Dispatchers.Main) {
val aVal = a() // statement 1
val bVal = b() // statement 2
resultTV.setText((aVal * bVal).toString()) // statement 3
}
:
:
}
suspend fun a(): Int {
delay(1_000L)
return 6
}
suspend fun b(): Int {
delay(1_000L)
return 7
}