GMS Task<TResult> class:如果 isSuccessful(),getResult() return 可以为 null 吗?

GMS Task<TResult> class: can getResult() return null if isSuccessful()?

最近对 GMS 任务库进行了 @Nullable 更改。反编译后的前几行.class 看起来像

public abstract class Task<TResult> {
    public Task() {
    }

    public abstract boolean isComplete();

    public abstract boolean isSuccessful();

    public abstract boolean isCanceled();

    @Nullable
    public abstract TResult getResult();

之前编译的 Kotlin 代码:

        if (task.isSuccessful) {
            task.result.user?.getIdToken(false)?.addOnCompleteListener { taskk ->
                this.emailIdTokenCompleteListener()(taskk)
            }

更新一些 gms play-services-zzz 依赖项后,代码现在有编译错误:

LoginActivity.kt: (148, 28): Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type AuthResult?

问题是,isSuccessful() == true是否意味着getResult != null?或者将 if 测试更改为 if (task.result != null)?

会更好吗?

您看到的是 Kotlin 编译器无法根据 isSuccessful 的结果将结果智能转换为 NonNull 类型,这可能在与 Java 和 Kotlin 代码交互时发生。

在 Kotlin 1.3 中,语言中添加了 "Contracts" 的实现,以允许开发人员以 IDE 可用于静态分析和推断类型的格式添加有关方法的元数据(智能投射)。

参见第 1.2 节 "Returns and Implies" https://proandroiddev.com/kotlin-contracts-make-great-deals-with-the-compiler-f524e57f11c

所以对于合同,如果实现看起来像这样,它会正确地智能投射:

open class Task<T> {
    var result: T? = null
        private set

    fun isSuccessful(): Boolean {
        contract {
            returns(true) implies (result != null)
        }
        return result != null
    }
}

然而,在你的情况下,你可能想使用另一个安全调用运算符 ? 并使用 Elvis 运算符 ?: 调用你的 !task.isSuccessful 代码,如下所示:

if (task.isSuccessful) {
        task.result?.user?.getIdToken(false)?.addOnCompleteListener { taskk ->
            this.emailIdTokenCompleteListener()(taskk)
        } ?: handleFailure() // Defensively call just in case
} else {
    handleFailure()
}

有 GMS 任务可以在运行时 return null。例如FirebaseAnalytics.getAppInstanceId()

所以你应该检查结果是否为空,而不是依赖注释。