Firestore (Kotlin) 在执行文档请求时将完整任务转换为密封 class 的正确方法

Firestore (Kotlin) proper way to convert a complete task into a sealed class when performing a document request

我正在尝试一种正确的方法,将一个完整的任务转换成一个密封的 class 在对文档执行获取请求时易于阅读(此时我将在稍后看到集合请求).

import com.google.android.gms.tasks.Task
import com.google.firebase.firestore.DocumentSnapshot
import com.google.firebase.firestore.FirebaseFirestoreException
import timber.log.Timber

fun <T> Task<DocumentSnapshot?>.toDocumentResult(parser: (documentSnapshotExisting: DocumentSnapshot) -> T): DocumentResult<T>?{
    val documentResult: DocumentResult<T> = if(isSuccessful){
        val documentSnapshot: DocumentSnapshot = result!!
        if(documentSnapshot.exists()){
            try {
                DocumentResult.Found(parser.invoke(documentSnapshot))
            }
            catch (e: java.lang.Exception){
                DocumentResult.ParserException<T>(documentId = documentSnapshot.id, e = e)
            }
        }else{
            DocumentResult.NotFound(documentSnapshot.id)
        }
    }else{
        DocumentResult.Error(exception!! as FirebaseFirestoreException)
    }
    documentResult.log()
    return documentResult
}


sealed class DocumentResult<T>{
    abstract fun log()

    class Found<T>(val o: T): DocumentResult<T>() {
        override fun log() {
            Timber.tag("DocumentResult").w("$o")
        }
    }

    class NotFound<T>(val documentId: String): DocumentResult<T>() {
        override fun log() {
            Timber.tag("DocumentResult").w("documentId: $documentId doesn't exist")
        }
    }

    class ParserException<T>(val documentId: String, val e: Exception): DocumentResult<T>() {
        override fun log() {
            Timber.tag("DocumentResult").e("ParserException: ${e.localizedMessage?:e.message?:"error"}, documentId: $documentId")
        }
    }

    class Error<T>(val e: FirebaseFirestoreException): DocumentResult<T>() {
        override fun log() {
            Timber.tag("DocumentResult").e("FirebaseFirestoreException - code: ${e.code.name}, ${e.localizedMessage?:e.message?:"error"}")
        }
    }
}

有了这个片段,我可以做到这一点:

activity.firestore.documentAvailableLanguages().get().addOnCompleteListener { task ->
    val documentResult = task.toDocumentResult { AvailableLanguages.toObject(it) }
    when(documentResult){
        is DocumentResult.Found -> { /* My converted object */ }
        is DocumentResult.NotFound -> {  /* document not found */}
        is DocumentResult.Error-> {  /* FirebaseFirestoreException */}
        is DocumentResult.ParserException -> { /* Conversion didn't work, exception */ }
    }
}

我的问题是:

1) 当 isSuccessFul 为 false 时,我们能否合理地确保 Task.exception 始终不为 null 和 FirebaseFirestoreException 的实例?

2) 当 task.isSuccessful 为真时,我们确定 task.result 始终不为空吗?

提前致谢

对于这两个问题,请注意 当任务所代表的工作按预期完成且没有错误时,任务为 "successful"。另一方面,当 Task 代表的工作完成时,Task 是 "complete",而不管它是 "success" 还是 "failure"。可能有错误也可能没有错误,您必须检查一下。

一个已经成功完成的任务 returns 一个 DocumentSnapshot 永远不会 具有 null 的值。如果请求的文档不存在,您将得到一个空的 DocumentSnapshot 对象,而不是 null。这也意味着如果您调用 exists():

documentSnapshot.exists() //Will returns false

如果正在调用 getData() 方法:

documentSnapshot.getData() //An exception will be thrown

如果 Taks 不是 "successful",则由 task.getException() 生成的异常是 FirebaseFirestoreException 的实例。请注意任务的 getException() 方法:

Returns the exception that caused the Task to fail. Returns null if the Task is not yet complete, or completed successfully.