创建Kotlin协程延迟对象,它发出侦听器回调结果

Lem*_*981 3 android kotlin rx-java kotlinx.coroutines

我目前正在一个项目中从RxJava切换到Kotlin协同程序,用coroutine aquivalents替换所有Single和Observable返回类型.我仍在努力使用以下构造:接口(例如存储库)提供数据查询访问并返回RxJava Single.该实现使用Single.create创建Single对象,并使用onSuccess/onError发出结果.现在,实现需要做的是检索数据是创建一个带有回调的监听器并将该监听器注册到某个东西.然后,创建的侦听器的回调将调用自制Single上的onSuccess/onError.例如使用firebase(虽然我的问题不是特定于firebase):

interface Repository {
    fun getData(query: Query): Single<DataSnapshot?>
}

fun getData(query: Query): Single<DataSnapshot?> = Single.create { emitter ->
    query.addListenerForSingleValueEvent(object : ValueEventListener {
        override fun onCancelled(error: DatabaseError?) {
            emitter.onError(Exception())
        }

        override fun onDataChange(data: DataSnapshot?) {
            emitter.onSuccess(data)
        }
    })
}
Run Code Online (Sandbox Code Playgroud)

现在我想要的是返回coroutine Deferred的接口方法.如何创建实现,以便还可以注册一个带回调的监听器,其结果将由Deferred传递?我没有看到这些协同构建器的方法,如异步,启动等,做onSuccess/onError会做什么.

interface Repository {
    fun getData(query: Query): Deferred<DataSnapshot?>
}
Run Code Online (Sandbox Code Playgroud)

Eri*_*ori 9

我的建议如下:

interface Repository {
    suspend fun getData(query: Query): Result<DataSnapshot>
}
Run Code Online (Sandbox Code Playgroud)

其中Result可以是具有Success和Error情况的密封类:

sealed class Result<T> {
    class Success<T>(result: T) : Result<T>()
    class Error<T>(error: String) : Result<T>()
}
Run Code Online (Sandbox Code Playgroud)

这样,在getData的实现方面你可以这样做:

return Success(yourData)
Run Code Online (Sandbox Code Playgroud)

要么

return Error("Something went wrong")
Run Code Online (Sandbox Code Playgroud)

通常在处理协同程序时,您应该避免返回延迟并尝试将它们用作"同步方法".

编辑:既然我理解了这个问题,我希望这有助于解决它:

//This is as generic as it gets, you could use it on any Query, no need to retype it
suspend fun Query.await(): DataSnapshot = suspendCoroutine{cont ->
    addListenerForSingleValueEvent(object : ValueEventListener{
        override fun onCancelled(error: DatabaseError?) {
            cont.resumeWithException(error?: Exception("Unknown Error"))
        }

        override fun onDataChange(data: DataSnapshot?) {
            if(data != null){
                cont.resume(data)
            } else {
                cont.resumeWithException(Exception("Null data"))
            }

        }
    })
}
//this is your actual implementation
suspend fun getData(query: Query):DataSnapshot =
        query.await()
Run Code Online (Sandbox Code Playgroud)

此代码假设DatabaseError扩展Exception或Throwable.如果不是,您需要为其创建包装类型或使用我的原始解决方案并在两种情况下使用常规简历.