我刚刚开始学习Kotlin协同程序,并试图模拟一些长时间的API调用,并在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
方法。
不幸的是,我无法找到有关the official tutorial for coroutines上某些特定主题的结果的信息。
答案 0 :(得分:9)
修改强>:
另见an official example in Kotlin repo
您需要实现Continuation界面,该界面可以回调Android UI线程和Coroutine context
e.g。 (来自here)
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())
}
更多信息:
答案 1 :(得分:9)
您应使用< NEED UI thread here >
项目UI
模块中的kotlinx-coroutines-android
上下文替换代码中的#to_sql
。它的用法在kotlinx.coroutines中有很多例子进行了解释。
答案 2 :(得分:4)
首先包括为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)
}
}
对于那些在gradle
中使用 kotlin experimental 作为 .aar 或 .apk公开项目的人 到其他项目模块 - 请记住,当您使用kotlin实验性父模块/项目时,必须接受 kotlin实验
kotlin {
experimental {
coroutines "enable"
}
}
答案 3 :(得分:0)
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;
}
答案 4 :(得分:0)
此问题可能在OP提出问题后2.5年,但在类似情况下仍可能会帮助其他人。
与上面接受的答案相比,无需使用async / await,可以以比上述公认的答案简单得多的方式实现原始目标(语句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
}