等待 Kotlin 协程在 onCreateView() 中完成

Coo*_*ind 8 kotlin kotlin-coroutines

我在 中有一个初始化块onCreateView,其中一些变量是从 SharedPreferences、DB 或 Network(当前来自 SharedPreferences)分配的。

我想在onViewCreated. 但是它们在协程onCreateView完成之前用空值更新。如何等到协程在主线程中完成?

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    ...
    GlobalScope.launch(Dispatchers.Main) {
        val job = GlobalScope.launch(Dispatchers.IO) {
            val task = async(Dispatchers.IO) {
                settingsInteractor.getStationSearchCountry().let {
                    countryName = it.name
                }
                settingsInteractor.getStationSearchRegion().let {
                    regionName = it.name
                }
            }
            task.await()
        }
        job.join()
    }
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    country.updateCaption(countryName)
    region.updateCaption(regionName)
}
Run Code Online (Sandbox Code Playgroud)

更新 (20-05-2019)

目前我不使用onViewCreated. 我在onCreate和 中编写代码onCreateView。在onCreateView我以这种方式访问​​视图:view.country.text = "abc"等等。

Ser*_*gey 5

在您的情况下,您不需要用GlobalScope作协程上下文(可以,但根据文档不建议这样做)。您需要一个本地范围:

private var job: Job = Job()
override val coroutineContext: CoroutineContext
    get() = Dispatchers.Main + job

@Override
public void onDestroy() {
    super.onDestroy();
    job.cancel()
}
Run Code Online (Sandbox Code Playgroud)

此外,您的片段应该实现并在 Android 中CoroutineScope使用,添加对应用程序的 build.gradle 的依赖关系:Dispatchers.Main

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.1'
Run Code Online (Sandbox Code Playgroud)

等待协程完成的代码:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    launch {
        val operation = async(Dispatchers.IO) {
            settingsInteractor.getStationSearchCountry().let {
                countryName = it.name
            }
            settingsInteractor.getStationSearchRegion().let {
                regionName = it.name
            }
        }
        operation.await() // wait for result of I/O operation without blocking the main thread

        // update views
        country.updateCaption(countryName)
        region.updateCaption(regionName)
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:

Activityor中Fragment,您可以使用lifecycleScope而不是实现CoroutineScope

lifecycleScope.launch { ... }
Run Code Online (Sandbox Code Playgroud)

要使用lifecycleScope将下一行添加到应用程序的build.gradle文件的依赖项中:

implementation "androidx.lifecycle:lifecycle-runtime-ktx:$LIFECYCLE_VERSION"
Run Code Online (Sandbox Code Playgroud)

在撰写最终版本时 LIFECYCLE_VERSION = "2.3.0-alpha05"


log*_*cat 5

最好使用async而不是launch https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html

创建lateinit val dataLoad: Deferred<Pair<String, String>. 将其初始化为dataLoad = GlobalScope.async(Dispatchers.Defailt) {}inonCreateView或更早。 launch.UI 范围内的新协程onViewCreated。等待该协程中的结果,val data = dataLoad.await()然后将数据应用于 ui