如何使用Kotlin协程等待第三方SDK的LiveData回调完成后执行操作?
用Kotlin协程等待LiveData回调完成对象初始化的解决方案
你的这段代码有个明显的问题:LiveData的observe是异步触发的,当你调用myCustomObject.doSomething()时,回调还没执行,myCustomObject肯定还是null,直接调用会触发空指针异常。用Kotlin协程可以优雅地解决这个异步等待的问题,下面给你两种实用的实现方式:
方法一:使用官方协程扩展库
如果你愿意引入官方的协程扩展依赖,可以直接用await()函数来挂起协程,直到LiveData返回值。
首先确保你的项目中引入了kotlinx-coroutines-play-services依赖(AndroidX环境下已适配LiveData),然后修改你的函数为suspend函数:
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import androidx.lifecycle.liveData suspend fun setValueAndDoSomething(activity: FragmentActivity) { // 切换到主线程观察LiveData(LiveData的observe方法要求在主线程执行) val sdkResult = withContext(Dispatchers.Main) { sdkComponent.await() // 挂起协程,直到LiveData发出第一个非null值 } val myCustomObject = MyCustomObject(sdkResult) myCustomObject.doSomething() }
说明:
await()是官方扩展函数,会自动挂起协程,直到LiveData有值返回;如果LiveData已经持有数据,会立即返回该值。- 必须用
withContext(Dispatchers.Main)切换到主线程,因为LiveData的观察者绑定操作只能在主线程执行。
方法二:自定义协程挂起函数(无额外依赖)
如果不想引入新依赖,可以自己实现一个suspend函数来等待LiveData的值:
import kotlinx.coroutines.suspendCancellableCoroutine import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import kotlin.coroutines.resume // 给LiveData添加自定义的suspend扩展函数 suspend fun <T> LiveData<T>.awaitValue(): T = suspendCancellableCoroutine { continuation -> val observer = Observer<T> { value -> value?.let { // 拿到值后恢复协程,并移除观察者避免内存泄漏 continuation.resume(it) removeObserver(observer) } } // 永久观察LiveData,直到拿到有效值 observeForever(observer) // 如果协程被取消,及时移除观察者,防止内存泄漏 continuation.invokeOnCancellation { removeObserver(observer) } } // 改造你的业务函数为suspend函数 suspend fun setValueAndDoSomething(activity: FragmentActivity) { val sdkResult = withContext(Dispatchers.Main) { sdkComponent.awaitValue() } val myCustomObject = MyCustomObject(sdkResult) myCustomObject.doSomething() }
说明:
- 用
suspendCancellableCoroutine将LiveData的回调逻辑转换成协程挂起逻辑,当LiveData发出非null值时,恢复协程并返回结果。 - 加入了协程取消的处理,确保即使协程被取消,也会移除观察者,避免内存泄漏。
注意事项
调用这个suspend函数时,必须在协程作用域内执行,比如在Activity/Fragment中用lifecycleScope,在ViewModel中用viewModelScope:
// 在Activity中调用的示例 lifecycleScope.launch { setValueAndDoSomething(this@MyActivity) }
这样就能保证myCustomObject完全初始化后,才会执行doSomething(),彻底避免空指针问题,同时代码逻辑更清晰,没有回调嵌套。
内容的提问来源于stack exchange,提问作者Matheus E.
相关产品推荐
相关产品推荐

