GMS Task <tresult>类:如果isSuccessful(),getResult()是否可以返回null?

时间:2018-11-13 22:08:21

标签: android kotlin google-play-services

最近对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):在AuthResult类型的可为空的接收器上仅允许安全(?。)或非空声明(!!。)调用?

问题是,isSuccessful() == true是否暗示着getResult != null?还是将if测试更改为if (task.result != null)会更好?

1 个答案:

答案 0 :(得分:1)

您看到的是Kotlin编译器无法基于isSuccessful的结果将结果智能广播到NonNull类型,这可能在与Java和Kotlin代码交互时发生。

在Kotlin 1.3中,该语言中添加了“合同”的实现,以允许开发人员以IDE可以用来静态分析和推断类型(智能广播)的格式添加有关方法的元数据。

请参见第1.2节“返回和暗示” 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()
}