Мое предложение выглядит следующим образом:
interface Repository {
suspend fun getData(query: Query): Result<DataSnapshot>
}
, где Result может быть запечатанным классом со случаями Success и Error:
sealed class Result<T> {
class Success<T>(result: T) : Result<T>()
class Error<T>(error: String) : Result<T>()
}
Таким образом, на стороне реализации getData выможет делать:
return Success(yourData)
или
return Error("Something went wrong")
В общем, при работе с сопрограммами вы должны избегать возврата отложенных значений и пытаться использовать их «как синхронные методы».
Edit: теперь, когда я понимаю проблему, я надеюсь, что это поможет решить ее:
//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 расширяет Exception или Throwable.Если нет, вам нужно создать для него тип оболочки или использовать мое оригинальное решение и использовать регулярное резюме в обоих случаях.