在协程的侦听器中等待数据

Wait For Data Inside a Listener in a Coroutine

我有一个协同程序,我想在初始页面期间 android 启动时启动。我想在开始下一个 activity 之前等待数据返回。做这个的最好方式是什么?目前我们的 android 正在使用实验性协程 0.26.0...目前还无法更改。

更新:我们现在使用最新的协同程序,不再是实验性的

onResume() {
    loadData()
}

fun loadData() = GlobalScope.launch {
    val job = GlobalScope.async {
        startLibraryCall()
    }
    // TODO await on success
    job.await()
    startActivity(startnewIntent)
}

fun startLibraryCall() {
    val thirdPartyLib() = ThirdPartyLibrary()
    thirdPartyLib.setOnDataListener() { 
        ///psuedocode for success/ fail listeners
        onSuccess -> ///TODO return data
        onFail -> /// TODO return other data
    }
}

第一点是,我会将您的loadData 函数更改为挂起函数,而不是使用launch。最好可以选择在调用站点定义您希望如何继续执行。例如,在实施测试时,您可能希望在 runBlocking 内调用协程。您还应该正确实施 structured concurrency 而不是依赖 GlobalScope.

在问题的另一边,我会在 ThirdPartyLibrary 上实现一个扩展函数,将它的异步调用变成一个挂起函数。这样您将确保调用协程实际上等待库调用在其中具有一些价值。

自从我们将 loadData 设为暂停函数后,我们现在可以确保它只会在 ThirdPartyLibrary 调用完成时启动新的 activity。

import kotlinx.coroutines.*
import kotlin.coroutines.*

class InitialActivity : AppCompatActivity(), CoroutineScope {
    private lateinit var masterJob: Job
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + masterJob

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        masterJob = Job()
    }

    override fun onDestroy() {
        super.onDestroy()
        masterJob.cancel()
    }

    override fun onResume() {
        this.launch {
            val data = ThirdPartyLibrary().suspendLoadData()
            // TODO: act on data!
            startActivity(startNewIntent)
        }
    }
}

suspend fun ThirdPartyLibrary.suspendLoadData(): Data = suspendCoroutine { cont ->
    setOnDataListener(
            onSuccess = { cont.resume(it) },
            onFail = { cont.resumeWithException(it) }
    )
    startLoadingData()
}

您可以使用 LiveData

liveData.value = job.await()

然后在onCreate()中加入例如

liveData.observe(currentActivity, observer)

在观察者中,只要等到值不为空,然后开始你的新 activity

Observer { result ->
            result?.let { 
                startActivity(newActivityIntent)
            } 
}