It seems Android Studio/Gradle 3.4 has introduced a new lint error DiffUtilEquals. It is triggered by having a DiffUtil<Any> and then calling as a fallback oldItem == newItem in the areContentsTheSame function. The error the linter throws is

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

Example code:

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

This when statement would be pretty common in a DiffUtil for an Adapter that has multiple types where you compare each type based on their class.

What is the best way to handle this error? Should <Any> be changed to some interface that is like Equatable or maybe all the classes used in the adapter should implement some interface that includes a way to compare them?

推荐答案

所有的java.lang.Object都有equals()功能.它是语言基础的一部分.然而,并不是所有的都覆盖它,这就是Linter正在触发的.(SomeClass() as Any).equals(SomeClass())可以很好地编译一个实例(当然,假设您有一个名为SomeClass的类).

我无法用任何一个类来重现这一点——它是你提到的那个(DiffUtil.ItemCallback).我扩大了判断范围,内容是:

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

判断信息:AreContents DiffUtil使用相同的内容来生成差异.如果该方法的实现不正确,例如使用identity equals而不是equals,或者对尚未实现它的类调用equals,则可能会出现奇怪的视觉瑕疵.

这个答案最好用不同的代码片段来演示:

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
    }

}

This will compile. If you don't know, a data class generates a custom equals method. If you, in Android Studio, remove the data keyword, the error will reappear, because there is no overridden equals method.

TL;DR: The inspection complains about a lack of a custom equals method, and/or the use of identity checking (== in Java or === in Kotlin). However, === will raise a separate message which is considerably easier to actually identify the solution to:

Suspicious equality check: Did you mean == instead of ===?

And I imagine == in Java raises a similar message, but with equals as the suggested replacement. I have not verified this

至于解决方案:

If you know what you're doing (NOT recommended)

您可以取消或更改错误的严重性.更改严重程度或全局 suppress 位于同一位置.文件->;设置->;编辑器->;判断>;Android->;Lint->;正确性->;可疑的DiffUtil相等

enter image description here

或者,您可以使用以下命令在本地 suppress 它:

@SuppressLint("DiffUtilEquals")

If you want to play it safe

不幸的是,这要复杂得多.

Anyno guarantee equals被覆盖-因此判断.唯一可行的 Select 是使用不同的类.使用Equatable也不是个坏主意.然而,与其他任何方法不同,这不是默认实现的.事实上,它并不存在于SDK中.然而,你可以自己创造一个.

The catch is, any of the implementing classes need an equals method now. If you use data classes, this isn't a problem (and I've demonstrated this in the code). However, if you don't, you'll need to implement it manually. Manually here either means you write it, or you otherwise have it generated (for an instance with annotations).

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

// Data classes generate the necessary equals methods. Equatable ensures all child classes do implement it, which fixes what the inspection wants you to fix.
data class One(val t: String) : Equatable  
data class Two(val title: String) : Equatable  

val x = object : DiffUtil.ItemCallback<Equatable /*Or a higher level inheritance model, i.e. a MySharedItemClass, where it either contains an abstract equals or implements Equatable. Implementing it doesn't require it to be abstract, but it depends on where you want the equals implementation. Equatable is an example of forced equals implementation, but there's many ways to Rome. */>() {
    override fun areItemsTheSame(p0: Equatable, p1: Equatable): Boolean {
        TODO("not implemented")
    }

    override fun areContentsTheSame(p0: Equatable, p1: Equatable): 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!
         }
    }
}

Kotlin相关问答推荐

在没有外部 map 的情况下转换列表项

如果一项工作失败,请继续在Kotlin 等待其他工作/子元素完成

为什么Kotlin协程程序即使有延迟也能输出?

jOOQ Kotlin Coroutines - Select all and exists查询

Kotlin 中命名构造函数的惯用方式

Kotlin:不允许在辅助构造函数参数上使用val

如何在 IntelliJ 中更改 Kotlin 的this property has a backing field代码编辑器突出显示?

从 Java 调用 Kotlin 高阶函数

在 Spring Framework 5.1 中注册具有相同名称的测试 bean

如何使 TextInputEditText 只读?

Kotlin DataBinding 将静态函数传递到布局 xml

无法在Kotlin中使用argb color int值?

Spring Boot:更改属性占位符符号

Kotlin:使用自定义设置器时没有lateinit的解决方法?

Kotlin - computed var 属性的用处?

如何将 CameraView 与 Jetpack Compose 一起使用?

可以在函数参数中使用解构吗?

Kotlin:测试中的 java.lang.NoSuchMethodError

Android studio,构建kotlin时出现奇怪错误:生成错误代码

Dagger 2 androidx fragment不兼容类型