Класс GMS Task <TResult>: может ли getResult () вернуть нуль, если isSuccessful ()?

1

Недавно в библиотеку задач 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 (task.result != null) на if (task.result != null)?

Теги:
kotlin
google-play-services

1 ответ

1
Лучший ответ

То, что вы видите, это то, что компилятору 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

Так что с контрактами было бы правильно smart-cast, если бы реализация выглядела так:

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()
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню