Почему я не могу использовать! _displayCheckBox.value, который не является нулевым изменяемым значением?

#android #kotlin

#Android #котлин

Вопрос:

Код A работает хорошо, я думаю _displayCheckBox.value , что он должен быть ненулевым, вы можете увидеть изображение A из командной строки Android Studio.

Я думаю, что у меня есть начальное значение _displayCheckBox using private val _displayCheckBox = MutableLiveData(false) , поэтому я думаю _displayCheckBox.value , что будет ненулевой MutableLiveData.

Но код B вызывает ошибку «Только безопасные (?.) или ненулевые утвержденные (!!.) Вызовы разрешены для обнуляемого получателя типа Boolean?», почему?

Код A

 private val _displayCheckBox = MutableLiveData(false)
val displayCheckBox : LiveData<Boolean> = _displayCheckBox

//Switch CheckBox On or Off
fun switchCheckBoxShowStatus(){
    _displayCheckBox.value?.let {
        _displayCheckBox.value = !it
    }
}
 

Код B

 private val _displayCheckBox = MutableLiveData(false)
val displayCheckBox : LiveData<Boolean> = _displayCheckBox

//Switch CheckBox On or Off
fun switchCheckBoxShowStatus(){
   _displayCheckBox.value = ! _displayCheckBox.value // It cause error.
}
 

Изображение A

введите описание изображения здесь

Добавленный контент

Я всегда буду получать «Значение равно false» для кода C. Поэтому я думаю, что _aa.value будет ненулевым при использовании val _aa = MutableLiveData(false) , верно?

Код C

  val _aa = MutableLiveData(false)
 Log.e("My","The  value is " _aa.value?:"null ")
 

Комментарии:

1. @Slaw В случае LiveData возвращаемый тип указан явно @Nullable T , потому что на самом value деле может быть null, даже если тип не является nullable , где null указывает, что значение еще не установлено. Возвращаемый тип не будет показывать ошибку, если вы обработаете его как ненулевой. Boolean!

2. @Tenfour04 Ах да, ты прав.

Ответ №1:

LiveData.getValue() специально аннотируется как возвращающий значение с нулевым значением, и поэтому Kotlin интерпретирует его как обнуляемое. Он обнуляется, потому что значение на самом деле равно null, если оно еще не было установлено.

Если вы хотите переключить его значение, вы можете указать резервное значение, когда оно равно нулю. И если вы дадите ему начальное значение при создании его экземпляра, вы знаете, что значение никогда не будет использовано.

Или вы могли бы создать свои собственные ненулевые BooleanLiveData, которые вводят начальное значение. С помощью подклассов вы можете сузить возвращаемый тип getValue from Boolean? до Boolean .

 class BooleanLiveData(initialValue: Boolean): MutableLiveData<Boolean>() {
    init {
        value = initialValue
    }

    override fun getValue(): Boolean = super.getValue() ?: false
}
 

Или вы можете использовать StateFlow вместо LiveData. Поток состояний вводит начальное значение.

Комментарии:

1. Спасибо! Вы имеете в виду значение _ displayCheckBox maybe null, даже если я напишу код private val _displayCheckBox = MutableLiveData(false)

2. Вопрос: А что, если бы ОП это сделал private val _displayCheckBox: MutableLiveData<Boolean> = MutableLiveData(false) ? Другими словами, сделайте тип явным. Сможет ли Kotlin тогда сказать, что значение не обнуляется? Или тот факт, что класс определен в Java, все еще мешает? Я бы проверил это, но на данный момент у меня нет подходящей среды.

3. Спасибо! Не могли бы вы, пожалуйста, посмотреть мой добавленный контент в вопросе?

4. Я думаю, вы оба задаете один и тот же вопрос. И ответ отрицательный. Компилятор Kotlin никак не может знать всю внутреннюю работу класса и определить, что значение не должно быть null, потому что ранее для объекта был вызван какой-то метод. Это происходит исключительно с помощью аннотации nullability, в которой говорится, что возвращаемое значение является обнуляемым. Если вы знаете, что вы уже установили значение хотя бы один раз или создали экземпляр класса с начальным значением, то вы, как программист, знаете, что оно никогда не будет null (потому что вы читали Javadocs для класса, поэтому вы знаете, что автор класса дал это обещание).

5. Так что в данном случае вы знаете больше, чем компилятор. Вы могли бы безопасно использовать !! в этой ситуации. Но было бы предпочтительнее использовать ?: error("Forgot to set initial value") вместо !! на всякий случай, если вы допустили ошибку, поэтому вы получите исключение, которое точно скажет вам, что нужно исправить.