Задача GMS <TResult>класс: может ли getResult () вернуть ноль, если isSuccessful ()? - PullRequest
0 голосов
/ 14 ноября 2018

Недавно в библиотеку задач 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 голосов
/ 14 ноября 2018

Вы видите, что компилятору Kotlin не удалось выполнить интеллектуальное приведение результата к типу NonNull на основе результата isSuccessful, это может произойти при взаимодействии как с Java, так и с кодом Kotlin.

В Kotlin 1.3 в язык была добавлена ​​реализация «Контрактов», чтобы позволить разработчикам добавлять метаданные о методе в формате, который IDE может использовать для статического анализа и вывода типа (smart-cast).

См. Раздел 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
    }
}

Однако в вашем случае вы, вероятно, захотите добавить другого оператора безопасного вызова ? и набрать свой код !task.isSuccessful с оператором Элвиса ?:, например:

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