姬長信(Redy)

android – 在运行主线程时对Cloud Firestore进…


我正在构建一个基于Android Clean Architecture Kotlin版本(https://github.com/android10/Android-CleanArchitecture-Kotlin)的应用程序.

使用此体系结构,每次要调用用例时,都会启动Kotlin协程,并将结果发布到主线程中.这是通过以下代码实现的:

abstract class UseCase where Type : Any {

abstract suspend fun run(params: Params): Either

fun execute(onResult: (Either) -> Unit, params: Params) {
    val job = async(CommonPool) { run(params) }
    launch(UI) { onResult.invoke(job.await()) }
}

在他的示例架构中,Android10先生使用Retrofit在kotlin couroutine中进行同步api调用.例如:

override fun movies(): Either> {
            return when (networkHandler.isConnected) {
                true -> request(service.movies(), { it.map { it.toMovie() } }, emptyList())
                false, null -> Left(NetworkConnection())
            }
        }

private fun  request(call: Call, transform: (T) -> R, default: T): Either {
            return try {
                val response = call.execute()
                when (response.isSuccessful) {
                    true -> Right(transform((response.body() ?: default)))
                    false -> Left(ServerError())
                }
            } catch (exception: Throwable) {
                Left(ServerError())
            }
        }

‘Either’表示不相交的类型,意味着结果将是失败或您想要的类型T的对象.

他的service.movi??es()方法实现如此(使用改造)

@GET(MOVIES) fun movies(): Call>

现在这是我的问题.我正在用Google Cloud Firestore取代改造.我知道目前,Firebase / Firestore是一个全异步库.我想知道是否有人知道一种更优雅的方法来对Firebase进行同步API调用.

我实现了自己的Call版本:

interface Call {
    fun execute(): Response

    data class Response(var isSuccessful: Boolean, var body: T?, var failure: Failure?)
}

?我的API调用在这里实现

override fun movieList(): Call> = object : Call> {
        override fun execute(): Call.Response> {
            return movieListResponse()
        }
    }

    private fun movieListResponse(): Call.Response> {
        var response: Call.Response>? = 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>
    }

当然,最后的while循环困扰着我.还有其他更优雅的方法,等待在从movieListResponse方法返回之前分配响应吗?

我尝试在从Firebase get()方法返回的Task上调用await(),但无论如何,movieListResponse方法都会立即返回.谢谢您的帮助!