https://blog.csdn.net/fitaotao/article/details/84314043
使用DiffUtil:DiffUtil是Android Support Library中的一个工具类,可以帮助计算新旧数据集的差异并高效更新RecyclerView的数据。通过使用DiffUtil,可以避免不必要的数据刷新和界面重绘,提高列表更新的效率。
fun <T> RecyclerView.Adapter<*>.autoNotify(old: List<T>, new: List<T>, compare: (T, T) -> Boolean) {
val diff = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return compare(old[oldItemPosition], new[newItemPosition])
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return old[oldItemPosition] == new[newItemPosition]
}
override fun getOldListSize() = old.size
override fun getNewListSize() = new.size
})
diff.dispatchUpdatesTo(this)
}
fun setData(list: List<MessageInfo>) {
autoNotify(messageList, list) { old, new ->
old.id == new.id
}
messageList.clear()
messageList.addAll(list)
// notifyItemRangeChanged(0, messageList.size)
}
在使用的过程中发现areContentsTheSame 中的old[oldItemPosition] == new[newItemPosition]这个比较,当其中某个字段发生变化后,比较结果仍为true。期望肯定是字段如发生变化,则需要返回false,更新这个Item。
分析出现上述问题的原因:
问题1:项目代码中,在adapter使用的list和外部list是同一个数据源,这就导致在比较之前,old和new的值就已经相同了。
问题2:使用==比较。在Kotlin中,这种比较方式默认调用的是equals方法进行比较,理想状态是对每个字段进行逐一比较,但是,实际情况并非如此,具体造成这个问题的原因在下文分解。
分析问题:
问题1:
这个问题其实按照上面的描述,其实就是自己在跟自己比较,所以恒为true。所以在adapter中,给adapter中的List进行赋值的时候,要注意使用不同的对象。利用bean的clone,给list进行一次重新赋值。
代码如下:
public static class MessageInfo implements Serializable , Cloneable{
@Override
public MessageInfo clone() {
MessageInfo o = null;
try{
o = (MessageInfo)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
return o;
}
}
问题2:
这个问题就比较奇怪了,根据对kotlin的理解,==比较就是调用equals进行比较,并且写过测试代码,当字段变化时,两个对象进行比较返回的是false。
data class Personal(val id:String, val name:String)
@Test
fun testEquals(){
val personal1 = Personal("1", "dy")
val personal2 = Personal("1", "dy")
println("$personal1 , $personal2")
val personal3 = Personal("1", "dy1")
val personal4 = personal2
assertEquals(true, personal1 == personal2 )
assertEquals(false, personal1 === personal2 )
assertEquals(false, personal1 === personal3 )
assertEquals(false, personal1 == personal3 )
assertEquals(true, personal4 == personal1 )
assertEquals(false, personal4 === personal1)
}
上述用例中,针对 kotlin 中的== === 进行了测试比较
其实这个问题的原因是项目中,虽然在调用处使用的是kotlin,但是bean文件是用Java创建的,这其实就涉及到一个java和kotlin混合使用的问题。那么问题究竟是什么呢?
我发现项目中的bean文件是java文件,而我的测试用例中,使用的是kotlin的data。
进一步验证问题,查看测试用例编译后生成的java代码:
public final class Personal {
@NotNull
private final String id;
@NotNull
private final String name;
@NotNull
public final String getId() {
return this.id;
}
@NotNull
public final String getName() {
return this.name;
}
public Personal(@NotNull String id, @NotNull String name) {
Intrinsics.checkNotNullParameter(id, "id");
Intrinsics.checkNotNullParameter(name, "name");
super();
this.id = id;
this.name = name;
}
@NotNull
public final String component1() {
return this.id;
}
@NotNull
public final String component2() {
return this.name;
}
@NotNull
public final Personal copy(@NotNull String id, @NotNull String name) {
Intrinsics.checkNotNullParameter(id, "id");
Intrinsics.checkNotNullParameter(name, "name");
return new Personal(id, name);
}
// $FF: synthetic method
public static Personal copy$default(Personal var0, String var1, String var2, int var3, Object var4) {
if ((var3 & 1) != 0) {
var1 = var0.id;
}
if ((var3 & 2) != 0) {
var2 = var0.name;
}
return var0.copy(var1, var2);
}
@NotNull
public String toString() {
return "Personal(id=" + this.id + ", name=" + this.name + ")";
}
public int hashCode() {
String var10000 = this.id;
int var1 = (var10000 != null ? var10000.hashCode() : 0) * 31;
String var10001 = this.name;
return var1 + (var10001 != null ? var10001.hashCode() : 0);
}
public boolean equals(@Nullable Object var1) {
if (this != var1) {
if (var1 instanceof Personal) {
Personal var2 = (Personal)var1;
if (Intrinsics.areEqual(this.id, var2.id) && Intrinsics.areEqual(this.name, var2.name)) {
return true;
}
}
return false;
} else {
return true;
}
}
}
通过上述代码发现了核心问题,在转为java代码的时候,data会自动生成equals比较方法。而我项目中自定义的java bean没有实现equals方法,这就导致在判断调用的时候,调用的是any默认的equals方法,仅会对引用进行比较,而不会对字段进行逐一的比较。。所以解决问的方案也一目了然,自己重写一下equals方法。另外要注意需要同时重写hashcode方法。
在Java中,当我们重写 equals() 方法时,通常也需要重写 hashCode() 方法。这是因为Java的 Object 类规定,如果两个对象相等(即 equals() 方法返回 true ),那么它们的 hashCode() 方法必须返回相同的值。如果你只重写了 equals() 方法而没有重写 hashCode() 方法,那么可能会违反这个规定,导致哈希表等数据结构的行为异常。
简单省事的解决方法就是直接用kotlin的bean, 并注意使用data class
滑动冲突:
http://wed.xjx100.cn/news/231642.html
https://blog.csdn.net/xiaokangss/article/details/128002513
混淆:
http://www.taodudu.cc/news/show-1258028.html?action=onClick
https://www.ngui.cc/el/1833760.html?action=onClick