Android开发拾遗:回调转协程

创建于:发布于:文集:Android开发拾遗

Kotlin提供了非常易用的協程API,但是在開發過程中遇到第三方SDK通過Java暴露出來的接口全是通過回調處理數據的情況。接口使用流程大致是:

val listener = object : ISomeInfoListener {
    override fun onInfoUpdate(info: Info) {
    }
}
 
SDK.getInstance().registerListener(listener)
 
SDK.getInstance().unregisterListener(listener)

當多個操作/數據之間存在先後依賴關係時,就容易陷入回調地獄,寫起來非常不舒服。

比如想在導航結束後,收集終點信息,存入數據庫,使用回調的形式寫:

val listener = object : IGuidanceListener {
    override fun onCompleted() {
        val destinationInfoListener = object : IDestinationInfoListener {
            override fun onArrived(info: Info) {
                scope.launch {
                    saveToDb(info)
                }
            }
        }
        SDK.getInstance().registerListener(destinationInfoListener)
    }
}
 
SDK.getInstance().registerListener(listener)

以上還是高度簡化後的代碼,實際場景下流程更複雜,代碼可讀性很低,修改起來也很麻煩。那麼有沒有辦法把一個回調操作封裝成 suspend ,以同步方式來組織呢?

可以使用 suspendCancellableCoroutine 來做。例如上面的操作,可以轉化爲:

suspend fun getSomeInfo(): Info = suspendCancellableCoroutine { continuation ->
    val listener = object : ISomeInfoListener {
        override fun onInfoUpdate(info: Info) {
            continuation.resume(info)
        }
    }
 
    SDK.getInstance().registerListener(listener)
 
    continuation.invokeOnCancellation { SDK.getInstance().unregisterListener(listener) }
}

在我使用的 Kotlin 2.1.0 版本中, continuation.resume 的函數簽名發生了一點變化:

continuation.resume(resourceToResumeWith) { cause, resourceToClose, context ->
    // resourceToResumeWith 和 resourceToClose 實際上是同一個值
    resourceToClose.close()
}

需要傳入一個 onCancellation 的回調,如果resume了一個需要關閉的Resource,可以用這個回調來處理。

EOF
文章有帮助?为我充个
版权声明