如何使用Kotlin协程等待()在主线程上
我刚开始学习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() { val aVal = a.await() val bVal = b.await() resultTV.setText((aVal * bVal).toString()) } } }
我不明白我怎么可能使用main
上下文launch
方法。
不幸的是,在协程的官方教程中 ,我无法find任何有关某些特定线程的结果。
编辑 :
另请参阅Kotlin回购中的官方示例
你需要实现Continuation接口,在Android UI线程和Coroutine上下文上进行回调
例如(从这里 )
private class AndroidContinuation(val cont: Continuation ) : Continuation 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 interceptContinuation(continuation: Continuation ): Continuation = AndroidContinuation(continuation) }
然后尝试:
launch(Android) { val aVal = a.await() val bVal = b.await() resultTV.setText((aVal * bVal).toString()) }
更多信息:
你应该用kotlinx.coroutines项目的kotlinx-coroutines-android
模块的UI
上下文替换代码中的< NEED UI thread here >
。 它的使用在“用户界面编程指南”中有详细说明。
首先包括为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) = mList.filter { ... } private fun filter() { val enumList = listOf(EnumX1, EnumX2) launch(UI){ val filteredList = getFilteredList(enumList) setMarkersOnMap(filteredList) } }
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; }