Android Studio - Korlin 协程 --> 未解决的引用:异步和启动

Android Studio - Korlin Coroutines --> Unresolved references: async & launch

我正在学习 Kotlin,我正在使用协程。

我在网上搜索了一下,是不是我用的方法太旧了?但我有异步和启动(UI)没有解决...

我的build.gradle:

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-android-extensions'
}

kotlin {
    experimental {
        coroutines 'enable'
    }
}
...
dependencies {

    implementation 'androidx.core:core-ktx:1.3.2'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation 'org.jetbrains.kotlin:kotlin-serialization'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
    implementation 'org.jetbrains.anko:anko-commons:0.10.1'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

}

从 api 获取数据的代码(已更新)

//getting data from api
fun fetchCharacterData(): Deferred<CharachterGenerator.CharacterData> {
    CoroutineScope(Main).launch {
        
           async {   val apiData = URL(CHARACTER_DATA_API).readText()
               CharachterGenerator.fromApiData(apiData)
           }
    }
       return <--- how to get this correct, what should I return?
}

我在按钮 setOnClickListener 中使用启动

generateButton.setOnClickListener {
            CoroutineScope(Main).launch {
            characterData = fetchCharacterData().await() 
            displayCharacterData()
            }
          }
        displayCharacterData()
    }

请告诉我,我还在学习...

launchasync是CoroutineScope的成员函数。你不能直接调用它们,除非你从一个实现了 CoroutineScope 的 class 中调用它们。您可能已经在 Kotlin 文档中看到了这一点,但它们的大多数示例都在 runBlocking lambda 中使用,它提供了一个作用域作为函数接收器。在 Android 上,您通常会使用提供给您的 CorotuineScopes,例如 lifecycleScopeviewModelScope

更新后编辑:

异步执行某事并return结果的函数的常见模式不是return延迟,而是使其成为直接return结果的挂起函数使用 withContext:

suspend fun fetchCharacterData() = withContext(Dispatchers.IO) {
    val apiData = URL(CHARACTER_DATA_API).readText()
    CharachterGenerator.fromApiData(apiData)
}

然后当你调用它时你的代码非常简单,因为你不必担心你在哪个调度程序上:

generateButton.setOnClickListener {
    lifecycleScope.launch {
        characterData = fetchCharacterData()
        displayCharacterData()
    }
}

使用类似于 CoroutineScope() 构造函数的函数来创建您未存储在 属性 中的一次性作用域是错误的,您可以在其中管理其生命周期。您应该很少需要创建自己的,因为 Android 为您提供 lifecycleScopeviewModelScope 并代表您管理它们的生命周期。

在浏览了其他几个文档之后,我设法做到了这一点

使用异步调用 API:

 fun fetchCharacterData(): Deferred<CharachterGenerator.CharacterData> {

    return CoroutineScope(IO).async  { val apiData = URL(CHARACTER_DATA_API).readText()
               CharachterGenerator.fromApiData(apiData)
           }
    }

发出请求并获取结果然后发送以显示

        generateButton.setOnClickListener {
            CoroutineScope(Main).launch {
                characterData = fetchCharacterData().await()
                displayCharacterData()
            }
        }