Я создаю приложение на основе версии Kotlin для Android Clean Architecture (https://github.com/android10/Android-CleanArchitecture-Kotlin).
). Используя эту архитектуру, каждый раз, когда вы хотите вызвать вариант использования, запускается сопрограмма Kotlin, и в результате получаетсяразмещено в главном потоке. Это достигается с помощью следующего кода:
abstract class UseCase<out Type, in Params> where Type : Any {
abstract suspend fun run(params: Params): Either<Failure, Type>
fun execute(onResult: (Either<Failure, Type>) -> Unit, params: Params) {
val job = async(CommonPool) { run(params) }
launch(UI) { onResult.invoke(job.await()) }
}
В своем примере архитектуры Mr. Android10 использует Retrofit для выполнения синхронного вызова API внутри процедуры kotlin. Например:
override fun movies(): Either<Failure, List<Movie>> {
return when (networkHandler.isConnected) {
true -> request(service.movies(), { it.map { it.toMovie() } }, emptyList())
false, null -> Left(NetworkConnection())
}
}
private fun <T, R> request(call: Call<T>, transform: (T) -> R, default: T): Either<Failure, R> {
return try {
val response = call.execute()
when (response.isSuccessful) {
true -> Right(transform((response.body() ?: default)))
false -> Left(ServerError())
}
} catch (exception: Throwable) {
Left(ServerError())
}
}
«Любой» представляет непересекающийся тип, означающий, что результатом будет либо Failure, либо объект типа T, который вы хотите.
Его метод service.movies () реализован таким образом (с использованием модернизации))
@GET(MOVIES) fun movies(): Call<List<MovieEntity>>
Теперь вот мой вопрос . Я заменяю модификацию на Google Cloud Firestore. Я знаю, что в настоящее время Firebase / Firestore является полностью асинхронной библиотекой. Я хочу знать, еслиКто-нибудь знает способ более элегантного способа сделать синхронный вызов API для Firebase.
Я реализовал свою собственную версию Call:
interface Call<T: Any> {
fun execute(): Response<T>
data class Response<T>(var isSuccessful: Boolean, var body: T?, var failure: Failure?)
}
и мой вызов API реализован здесь
override fun movieList(): Call<List<MovieEntity>> = object : Call<List<MovieEntity>> {
override fun execute(): Call.Response<List<MovieEntity>> {
return movieListResponse()
}
}
private fun movieListResponse(): Call.Response<List<MovieEntity>> {
var response: Call.Response<List<MovieEntity>>? = null
FirebaseFirestore.getInstance().collection(DataConfig.databasePath + MOVIES_PATH).get().addOnCompleteListener { task ->
response = when {
!task.isSuccessful -> Call.Response(false, null, Failure.ServerError())
task.result.isEmpty -> Call.Response(false, null, MovieFailure.ListNotAvailable())
else -> Call.Response(true, task.result.mapTo(ArrayList()) { MovieEntity.fromSnapshot(it) }, null)
}
}
while (response == null)
Thread.sleep(50)
return response as Call.Response<List<MovieEntity>>
}
Конечно, цикл while в конце беспокоит меня. Есть ли другие, более изящные способы, чтобы ждатьответ, который должен быть назначен до возврата из метода movieListResponse
?
Я попытался вызвать await () для Задачи, возвращаемой из метода Firebase get()
, но метод movieListResponse
в любом случае немедленно вернется.Спасибо за помощь!