Kotlin中使用Java数据类时引发的Bug解决方式

 更新时间:2023年09月26日 14:59:19   作者:_小马快跑_  
这篇文章主要介绍了Kotlin中使用Java数据类时引发的一个Bug,本文给大家分享问题解决方式,感兴趣的朋友跟随小编一起看看吧

基础复习:Kotlin语言中的对象比较

比较对象的内容是否相等 (== 或者 equals ) :Kotlin 中的操作符 == 和 equals效果相同 ,都用于比较对象的内容是否相等, Kotlin中建议直接使用 ==。

比较对象的引用是否相等 ( === ) :Kotlin 中的操作符 === 用于比较对象的引用是否指向同一个地址,运行时如果是基本数据类型 === 等价于 ==。

背景

如图效果,通过RecyclerView实现,每次通过对每个Item前后数据进行对比来确定执行什么操作(如Item的insert、update、delete等),这里使用RecyclerView库中的DiffUtil.Callback()来进行的前后数据对比,如下示例:

class DataDiffUtil(private val oldModels: List<Any>, private val newModels: List<Any>) :DiffUtil.Callback() {
    /**
     * 旧数据
     */
    override fun getOldListSize(): Int = oldModels.size
    /**
     * 新数据
     */
    override fun getNewListSize(): Int = newModels.size
    /**
     * DiffUtil调用来决定两个对象是否代表相同的Item。true表示两个Item相同(表示View可以复用),false表示不相同(View不可以复用)
     * 例如,如果你的项目有唯一的id,这个方法应该检查它们的id是否相等。
     */
    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldModels[oldItemPosition]::class.java == newModels[newItemPosition]::class.java
    }
    /**
     * 比较两个Item是否有相同的内容(用于判断Item的内容是否发生了改变),
     * 该方法只有当areItemsTheSame (int, int)返回true时才会被调用。
     */
    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        return oldModels[oldItemPosition] == newModels[newItemPosition]
    }
    /**
     * 该方法执行时机:areItemsTheSame(int, int)返回true 并且 areContentsTheSame(int, int)返回false
     * 该方法返回Item中的变化数据,用于只更新Item中变化数据对应的UI
     */
    override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? {
        return super.getChangePayload(oldItemPosition, newItemPosition)
    }
}

以顶部的Item1 模块举例,当服务端有新数据来时,通过下面方式进行更新:

/**
 * use[DiffUtil] 增量更新数据
 * @param newList 新数据
 */
fun submitList(newList: MutableList<Any>) {
    //传入新旧数据进行比对
    val diffUtil = DataDiffUtil(mModels, newList)
    //经过比对得到差异结果
    val diffResult = DiffUtil.calculateDiff(diffUtil)
    //NOTE:注意这里要重新设置Adapter中的数据
    setModels(newList)
    //将数据传给adapter,最终通过adapter.notifyItemXXX更新数据
    diffResult.dispatchUpdatesTo(this)
}

如果 Item1 前后数据是一样的,那么 DiffUtil.Callback#areContentsTheSame() 中的 oldModels[oldItemPosition] == newModels[newItemPosition] 理论上返回的就是true,Item1 模块也不会执行刷新操作了。

实际跑起来能按我们的预期走吗?

问题出现

上述逻辑写的差不多了,还差 Model 数据类没有写出来,因为项目中是 Kotlin & Java 混用的,而 Model 数据类正好是用Java语言编写的:

public class VP2Model implements Serializable {
    public int id;
    public String content;
}

看上去一切都是OK的,但是运行之后发现出问题了,即使前后数据完全一样,仍然会进行 Item1 的刷新,说明 DiffUtil.Callback#areContentsTheSame() 里的数据对比返回的是 false ,通过断点发现确实返回了false。

到这里不知道大家有没有发现问题所在?开始以为是数据变了,但是通过Log打点发现前后数据是一样的,那么明明是一样的,为什么对比会是不同呢?仔细一想明白了,问题出在Java语言上,出在VP2Model类中没有重新equals()方法

@Override
public boolean equals(@Nullable Object obj) {
    return super.equals(obj);
}

Java Model 类默认的 equals() 方法是比较的对象内存地址,刷新前后生成的显然不是同一个对象,那么前后地址对比返回的肯定是false了,问题就出在了这里!

如果我们使用 Kotlin 语言编写 Model 类就不会有这个问题,因为 Kotlin 编译器自动帮我们重写了 equals()/hashCode() 方法,如:

data class VP2Model(
    val id: Int = 0,
    val content: String = "",
)

注意这里要用 data class 开头才行,上述代码转换成 Java 后:

Kotlin data class类转换成Java类自动复写的方法

可以看到 Kotlin 编写的 Model 类自动帮我们实现了其中的 equals()/hashCode() 方法。

解决方式

已经知道问题出现的原因,那么解决方式就很简单了,比如下面几种解决方式:

方式一

重写 Java Model 类中的 equals() 方法,对每个字段进行对比,字段都相同返回 true,否则返回 false。

有一种快捷生成方式,在 Mac 版的 AS 中,可以使用 command + N 的方式生成,如下:

Java中自动实现equals()、hashCode()方法

生成结果:

自动生成

方式二

在使用的地方用 Kotlin 语言编写 Model 类进行转换,注意:这里一定要用 data class 开头的声明,因为 Kotlin 编译器会自动帮我们重写 equals()/hashCode() 方法。

到此这篇关于Kotlin中使用Java数据类时引发的一个Bug的文章就介绍到这了,更多相关Kotlin使用Java数据类引发的bug内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Springboot整合Shiro实现登录与权限校验详细解读

    Springboot整合Shiro实现登录与权限校验详细解读

    本文给大家介绍Springboot整合Shiro的基本使用,Apache Shiro是Java的一个安全框架,Shiro本身无法知道所持有令牌的用户是否合法,我们将整合Shiro实现登录与权限的验证
    2022-04-04
  • IDEA中SpringBoot项目的yml多环境配置方式

    IDEA中SpringBoot项目的yml多环境配置方式

    这篇文章主要介绍了IDEA中SpringBoot项目的yml多环境配置,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2023-10-10
  • 如何使用spring ResponseEntity处理http响应

    如何使用spring ResponseEntity处理http响应

    这篇文章主要介绍了如何使用spring ResponseEntity处理http响应的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • IDEA自定义pom依赖的步骤详解

    IDEA自定义pom依赖的步骤详解

    这篇文章主要介绍了IDEA自定义pom依赖的步骤详解,本文分步骤通过图文并茂的形式给大家介绍的非常详细对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • 基于Java代码实现游戏服务器生成全局唯一ID的方法汇总

    基于Java代码实现游戏服务器生成全局唯一ID的方法汇总

    我们在做服务器系统开发的时候,为了适应数据大并发的请求,需要插入数据库之前生成一个全局的唯一id,纠结全局唯一id怎么生成呢?下面小编给大家分享Java代码实现游戏服务器生成全局唯一ID的方法汇总,涉及到优劣势方面的知识点,对此感兴趣的朋友一起看看吧
    2016-10-10
  • Java抽象类的构造模板模式用法示例

    Java抽象类的构造模板模式用法示例

    这篇文章主要介绍了Java抽象类的构造模板模式用法,结合实例形式分析了java使用抽象类构造模板模式相关操作技巧,需要的朋友可以参考下
    2019-09-09
  • JAVA多线程实现生产者消费者的实例详解

    JAVA多线程实现生产者消费者的实例详解

    这篇文章主要介绍了JAVA多线程实现生产者消费者的实例详解的相关资料,需要的朋友可以参考下
    2017-06-06
  • java中Hutool包的常用方法总结

    java中Hutool包的常用方法总结

    这篇文章主要为大家详细介绍了java在工作中中Hutool包的一些常用方法总结,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-12-12
  • Java实现音频添加自定义时长静音的示例代码

    Java实现音频添加自定义时长静音的示例代码

    这篇文章主要介绍了一个Java工具类,可以实现给一个wav音频添加自定义时长静音。文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编学习一下
    2022-01-01
  • MySQL中drop、truncate和delete的区别小结

    MySQL中drop、truncate和delete的区别小结

    在MySQL数据库管理中,常常需要执行删除数据的操作,本文主要介绍了MySQL中drop、truncate和delete的区别小结,具有一定的参考价值,感兴趣的可以了解一下
    2024-04-04

最新评论