我正在尝试使用Kotlin的协同程序来避免回调地狱,但在这种特殊情况下它看起来并不像我能想到的那样。我希望能有一些关于它的事情。
我有这个SyncService类,它调用一系列不同的方法将数据发送到服务器,如下所示: SyncService调用Sync Student,它调用Student Repository,它调用DataSource,使服务器请求通过Apollo的Graphql Client发送数据。 我的每个功能都遵循相同的模式:
SyncService - >同步功能 - >功能存储库 - >数据源
所以我调用的每个方法都有这个签名:
fun save(onSuccess: ()-> Unit, onError:()->Unit) {
//To Stuff here
}
问题是: 当我在服务器上同步并成功保存学生时,我需要同步他的注册,如果我成功保存了注册,我需要同步另一个对象,依此类推。 这一切都取决于彼此,我需要按顺序执行,这就是我使用回调的原因。 但是你可以想象,代码结果不是很友好,我和我的团队开始寻找替代方案以保持更好。我们最终得到了这个扩展功能:
suspend fun <T> ApolloCall<T>.execute() = suspendCoroutine<Response<T>> { cont ->
enqueue(object: ApolloCall.Callback<T>() {
override fun onResponse(response: Response<T>) {
cont.resume(response)
}
override fun onFailure(e: ApolloException) {
cont.resumeWithException(e)
}
})
}
但是DataSource中的函数仍然有onSuccess()和onError()作为回调,需要传递给任何调用它的人。
fun saveStudents(
students: List<StudentInput>,
onSuccess: () -> Unit,
onError: (errorMessage: String) -> Unit) {
runBlocking {
try {
val response = GraphQLClient.apolloInstance
.mutate(CreateStudentsMutation
.builder()
.students(students)
.build())
.execute()
if (!response.hasErrors())
onSuccess()
else
onError("Response has errors!")
} catch (e: ApolloException) {
e.printStackTrace()
onError("Server error occurred!")
}
}
}
SyncService类代码更改为:
private fun runSync(onComplete: () -> Unit) = async(CommonPool) {
val syncStudentProcess = async(coroutineContext, start = CoroutineStart.LAZY) {
syncStudents()
}
val syncEnrollmentProcess = async(coroutineContext, start = CoroutineStart.LAZY) {
syncEnrollments()
}
syncStudentProcess.await()
syncEnrollmentProcess.await()
onComplete()
}
它会按顺序执行它,但如果有任何错误,我需要一种方法来阻止其他所有协程。错误可能只来自阿波罗的 所以我一直在努力寻找一种简化代码的方法,但没有得到任何好的结果。我甚至不知道这种回调的链接是否可以简化。这就是为什么我来这里看一些想法。 TLDR:我想要一种顺序执行所有函数的方法,并且如果有任何异常没有很多链接回调,仍然能够停止所有协同程序。