Ошибка Lint: подозрительная проверка на равенство: equals () не реализован в Object DiffUtilEquals - PullRequest
4 голосов
/ 29 апреля 2019

В Android Studio / Gradle 3.4 появилась новая ошибка lint DiffUtilEquals.Он запускается при наличии DiffUtil<Any> и последующем вызове oldItem == newItem в функции areContentsTheSame.Ошибка, которую выдает линтер:

Suspicious equality check: equals() is not implemented in Object

Пример кода:

 override fun areContentsTheSame(oldItem: Any, newItem: Any): Boolean {
        return when {
            oldItem is MyKotlinClass && newItem is MyKotlinClass -> true
            oldItem is MyKotlinClass2 && newItem is MyKotlinClass2 -> oldItem.title == newItem.title
            else -> oldItem == newItem // Lint error on this line
        }
    }

Этот оператор when будет довольно распространенным в DiffUtil для адаптера, который имеет несколько типов, где вы сравниваете каждый тип на основев их классе.

Как лучше всего справиться с этой ошибкой?Следует ли заменить <Any> на какой-то интерфейс, подобный Equatable, или, может быть, все классы, используемые в адаптере, должны реализовывать некоторый интерфейс, который включает способ их сравнения?

1 Ответ

8 голосов
/ 29 апреля 2019

Все java.lang.Object имеют функцию equals(). Это часть основы языка. Однако не все переопределяют его, и это то, что запускает линтер. (SomeClass() as Any).equals(SomeClass()) прекрасно скомпилируется для экземпляра (если, конечно, у вас есть класс с именем SomeClass).

Я не мог воспроизвести это ни с одним классом - у него было , которое вы упомянули (DiffUtil.ItemCallback). Я расширил инспекцию, которая говорит:

Подозрительная проверка на равенство: функция equals () не реализована в Object

Информация о проверке: areContentsTheSame используется DiffUtil для создания различий. Если метод реализован неправильно, например, при использовании идентификаторов равных вместо равных или при вызове равных в классе, который его не реализовал, могут возникнуть странные визуальные артефакты.

Этот ответ лучше всего продемонстрировать в другом фрагменте:

data class One(val t: String)

val x = object : DiffUtil.ItemCallback<One>() {
    override fun areItemsTheSame(p0: One, p1: One): Boolean { TODO() }
    override fun areContentsTheSame(p0: One, p1: One): Boolean {
        return p0 == p1
    }

}

Это скомпилируется. Если вы не знаете, data class генерирует пользовательский метод equals. Если в Android Studio удалить ключевое слово data, ошибка появится снова, поскольку переопределенный метод получения отсутствует.

TL; DR: Инспекция жалуется на отсутствие пользовательского equals метода и / или использования проверки личности (== в Java или * 1032) * в Котлине). Тем не менее, === выдаст отдельное сообщение, которое на самом деле значительно проще идентифицировать решение:

Подозрительная проверка на равенство: Вы имели в виду == вместо ===?

И я представляю, == в Java вызывает подобное сообщение, но с equals в качестве предлагаемой замены. Я не проверял это

Что касается решений:

Если вы знаете, что делаете

Вы можете подавить или изменить серьезность ошибки. Изменение серьезности или подавление глобально - там же. Файл -> Настройки -> Редактор -> Проверки> Android -> Lint -> Корректность -> Подозрительный DiffUtil равенства

enter image description here

Или вы можете подавить его локально с помощью:

@SuppressLint("DiffUtilEquals")

Если вы хотите быть осторожным

Это, к сожалению, сложнее.

Any имеет без гарантии equals отменено - следовательно, проверка. Единственный возможный вариант - использовать другой класс. И использование Equatable тоже неплохая идея. Однако, в отличие от Any, по умолчанию это не реализовано. На самом деле его нет в SDK. Но Kotlin позволяет легко исправить. Вы можете создать это самостоятельно.

Уловка в том, что любой из реализующих классов теперь нуждается в метод equals. Если вы используете data class es, это не проблема (и я продемонстрировал это в коде). Однако, если вы этого не сделаете, вам нужно будет реализовать это вручную. Или я представляю с аннотацией, но вам, вероятно, придется создать ее самостоятельно или найти библиотеку, которая добавляет такую ​​функциональность.

interface Equatable  {
    override fun equals(other: Any?) : Boolean;
}

data class One(val t: String) : Equatable  
data class Two(val title: String) : Equatable  

val x = object : DiffUtil.ItemCallback<MySharedItemClass>() {
    override fun areItemsTheSame(p0: MySharedItemClass, p1: MySharedItemClass): Boolean {
        TODO("not implemented")
    }

    override fun areContentsTheSame(p0: MySharedItemClass, p1: MySharedItemClass): Boolean {
         return when {
             p0 is One && p1 is One -> true
             p0 is Two && p1 is Two -> p0.title == p1.title
             else -> p0 == p1 // No error!
         }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...