在协程的侦听器中等待数据
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)
}
}
我有一个协同程序,我想在初始页面期间 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)
}
}