Android 创建发出侦听器回调结果的Kotlin协同路由延迟对象
我目前正在一个项目中从RxJava切换到Kotlin协程,用协程aquivalent替换所有单一和可观察的返回类型。我仍在为以下构造而挣扎:接口(例如存储库)提供数据查询访问并返回一个RxJava单变量。该实现使用Single.create创建单个对象,并使用onSuccess/onError发送结果。现在,实现需要做的是检索数据,创建一个带有回调的侦听器,并将该侦听器注册到某个对象。然后,所创建侦听器的回调将调用自制单上的onSuccess/onError。例如,使用firebase(尽管我的问题不是针对firebase):Android 创建发出侦听器回调结果的Kotlin协同路由延迟对象,android,kotlin,rx-java,kotlinx.coroutines,Android,Kotlin,Rx Java,Kotlinx.coroutines,我目前正在一个项目中从RxJava切换到Kotlin协程,用协程aquivalent替换所有单一和可观察的返回类型。我仍在为以下构造而挣扎:接口(例如存储库)提供数据查询访问并返回一个RxJava单变量。该实现使用Single.create创建单个对象,并使用onSuccess/onError发送结果。现在,实现需要做的是检索数据,创建一个带有回调的侦听器,并将该侦听器注册到某个对象。然后,所创建侦听器的回调将调用自制单上的onSuccess/onError。例如,使用firebase(尽管我的
接口存储库{
fun getData(查询:查询):单个
}
fun getData(query:query):Single=Single.create{emitter->
query.addListenerForSingleValueEvent(对象:ValueEventListener{
覆盖已取消(错误:DatabaseError?){
emitter.onError(异常())
}
覆盖数据更改(数据:DataSnapshot?){
发射器.onSuccess(数据)
}
})
}
现在我想要的是返回coroutine Deferred的接口方法。必须如何创建实现,以便还可以注册一个具有回调的侦听器,其结果随后将由延迟服务器交付?我看不到像async、launch等这样的Corroutine构建器可以做onSuccess/onError会做的事情
interface Repository {
fun getData(query: Query): Deferred<DataSnapshot?>
}
接口存储库{
fun getData(查询:查询):延迟
}
我的建议如下:
interface Repository {
suspend fun getData(query: Query): Result<DataSnapshot>
}
或
一般来说,在处理协同程序时,您应该避免返回延迟,并尝试将它们“用作同步方法”
编辑:
现在我了解了这个问题,我希望这有助于解决它:
//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()
此代码假定DatabaseError扩展了异常或Throwable。如果不是,你需要为它创建一个包装类型,或者使用我的原始解决方案,并在这两种情况下使用常规简历。我认为我要寻找的最接近的东西是ReceiveChannel。提出了以下解决方案:
override fun getData(query: Query): ReceiveChannel<Datasnapshot?> = GlobalScope.produce {
query.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(data: DataSnapshot?) {
launch { send(data) } }
}
override fun onCancelled(error: DatabaseError?) {
throw Exception()
}
})
}
override fun getData(query:query):ReceiveChannel=GlobalScope.product{
query.addListenerForSingleValueEvent(对象:ValueEventListener{
覆盖数据更改(数据:DataSnapshot?){
启动{send(data)}
}
覆盖已取消(错误:DatabaseError?){
抛出异常()
}
})
}
不确定这是否有点过分,是否会有更好的方法,欢迎建议如果您正在从Rx切换到协同程序,那么您应该从单一功能转到挂起功能:挂起fun getData(查询:查询):DataSnapshot?根据经验,您不应该有返回延迟的函数。好的,我会这样做,但仍然不知道如何实现,如何从侦听器获取并回调到挂起函数所需的返回值DataSnapshot?仍然没有解决问题。我无法从作为挂起函数返回类型的回调方法中返回任何内容。这就是为什么Single.create构造首先是如何完成的。现在我对这个问题有了更好的理解。遗憾的是,我现在没有时间解释如何从这种情况转换为协同工作。但在2017年kotlin conf中有两次关于协同程序的讨论深入解释了它们,第二次讨论解释了如何做这类事情。
return Success(yourData)
return Error("Something went wrong")
//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()
override fun getData(query: Query): ReceiveChannel<Datasnapshot?> = GlobalScope.produce {
query.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(data: DataSnapshot?) {
launch { send(data) } }
}
override fun onCancelled(error: DatabaseError?) {
throw Exception()
}
})
}