【问题标题】:Wait For Data Inside a Listener in a Coroutine在协程中等待侦听器内的数据
【发布时间】:2018-11-05 20:41:28
【问题描述】:

我有一个协程,我想在启动页面的 android 启动时启动。在开始下一个活动之前,我想等待数据返回。做这个的最好方式是什么?目前我们的 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
    }
}

【问题讨论】:

    标签: android kotlin kotlinx.coroutines


    【解决方案1】:

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

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

    由于我们将loadData 设为挂起函数,我们现在可以确保它只会在ThirdPartyLibrary 调用完成时启动新活动。

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

    【讨论】:

    • 好吧,看起来不错。但图书馆是第三方,我无法接听电话。我能做的就是倾听听众的声音
    • 这个答案不需要对库进行任何更改,它完全建立在您指定的成分之上。它的作用是向您展示如何使用侦听器来构造suspend fun。一旦你有了它,你就不需要任何async-await 逻辑。
    • 协程的东西仍然很新,而且一直在不断变化,我仍然不确定最佳实践。但是谢谢这个战利品很好,我会测试一下,看看我能不能让它工作。
    • 什么是suspendCoroutine
    【解决方案2】:

    你可以使用 LiveData

    liveData.value = job.await()
    

    然后以 onCreate() 为例

    liveData.observe(currentActivity, observer)
    

    在观察者中等待直到值不为空,然后开始你的新活动

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

    【讨论】:

    • Google 不提倡明确使用job API
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    相关资源
    最近更新 更多