Wait until Kotlin coroutine finishes in onCreateView()

假如想象 提交于 2019-12-23 13:05:10

问题


I have an initialization block in onCreateView, where some variables are assigned from SharedPreferences, DB or Network (currently from SharedPreferences).

I want to update views with these values in onViewCreated. But they update with empty values before a coroutine in onCreateView finishes. How to wait until the coroutine finishes in main thread?

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)
}

UPDATE (20-05-2019)

Currently I don't use onViewCreated. I write code in onCreate and onCreateView. In onCreateView I access views this way: view.country.text = "abc" and so on.


回答1:


In your case you don't need to use GlobalScope as a coroutine context (you can but it is not recommended as per docs). You need a local scope:

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

@Override
public void onDestroy() {
    super.onDestroy();
    job.cancel()
}

Also your fragment should implement CoroutineScope and to use Dispatchers.Main in Android add dependency to app's build.gradle:

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.1'

The code to wait until the coroutine finishes:

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)
    }
}



回答2:


It's better to use async instead of launch https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html.

Create lateinit val dataLoad: Deferred<Pair<String, String>. init it as dataLoad = GlobalScope.async(Dispatchers.Defailt) {} in onCreateView or earlier. launch new coroutine in UI scope in onViewCreated. Wait for result in that coroutine val data = dataLoad.await() and then apply data to ui



来源:https://stackoverflow.com/questions/53665470/wait-until-kotlin-coroutine-finishes-in-oncreateview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!