Kotlinコルーチンの学習を始めたばかりで、UIに結果を表示して、長時間のAPI呼び出しをシミュレートしようとしていました。
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
コンテキストで使用する方法がわかりません。
残念ながら、 コルーチンの公式チュートリアル で特定のスレッドの結果を提供することについては何も見つかりませんでした。
編集:
Kotlinリポジトリの公式例 も参照してください
Android UIスレッドと コルーチンコンテキスト にコールバックを行う 継続 インターフェースを実装する必要があります
例えば( ここ から)
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())
}
より詳しい情報:
コード内の< NEED UI thread here >
を kotlinx.coroutines プロジェクトのkotlinx-coroutines-Android
モジュールからのUI
コンテキストに置き換える必要があります。その使用法は コルーチンを使用したUIプログラミングのガイド でかなりの数の例で説明されています。
まず第一に、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"
}
}
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年後の可能性がありますが、それでも同様の状況で他の人を助ける可能性があります。
元の目標は、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
}