神马笔记 版本1.8.0——删除笔记/文件夹·技术细节篇

神马笔记 版本1.8.0——删除笔记/文件夹·技术细节篇

一、目标

记录开发过程中的2个技术问题。

  1. 拖拽排序问题
  2. indexOf问题

二、体验地址

神马笔记最新版本下载:【神马笔记 版本1.8.0——删除笔记/文件夹功能.apk

三、技术问题

1. 拖拽排序问题

ItemTouchHelper.Callback#onMove()方法应该怎么实现?

1
2
public abstract boolean onMove(@NonNull RecyclerView recyclerView,
@NonNull ViewHolder viewHolder, @NonNull ViewHolder target);
  • 实现一
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//滑动事件 下面注释的代码,滑动后数据和条目错乱,被舍弃
// Collections.swap(datas,viewHolder.getAdapterPosition(),target.getAdapterPosition());
// ap.notifyItemMoved(viewHolder.getAdapterPosition(),target.getAdapterPosition());

//得到当拖拽的viewHolder的Position
int fromPosition = viewHolder.getAdapterPosition();
//拿到当前拖拽到的item的viewHolder
int toPosition = target.getAdapterPosition();
if (fromPosition < toPosition) {
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(datas, i, i + 1);
}
} else {
for (int i = fromPosition; i > toPosition; i--) {
Collections.swap(datas, i, i - 1);
}
}
ap.notifyItemMoved(fromPosition, toPosition);
return true;
}

代码来自:《RecyclerView拖拽排序》。

  • 实现二
1
2
3
4
5
6
7
8
9
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
//直接按照文档来操作啊,这文档写得太给力了,简直完美!
adapter.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());

//注意这里有个坑的,itemView 都移动了,对应的数据也要移动
Collections.swap(list, viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}

代码来自:《RecyclerView的item拖动排序效果实现和它的ItemTouchHelper详解》。

  • 实现三
1
2
3
4
5
6
7
8
9
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
int from = viewHolder.getAdapterPosition();
int to = target.getAdapterPosition();

list.add(to, list.remove(from));

adapter.notifyItemMoved(from, to);
}

代码来自:神马笔记

  • 方案结果
结果 备注
方案一 正确
方案二 错误 快速拖动进行排序时,必然会导致顺序混乱。
方案三 正确

方案一和方案三是正确的。

方案二在逐个依次拖拽排序,不会出现问题。当快速拖动,超过2个列表项时,则会发生顺序混乱。

原因何在?

onMove方法指的是viewHolder移动到target的位置,而不是二者交换。

例如:初始列表:

A B C D E F G

将A移动到E的位置,结果是:

B C D E A F G

而A与E交换位置,结果是:

E B C D A F G

onMove方法要求的是移动操作,而Collections#swap实现的是交换操作,因此必然导致顺序发生换乱。

2. indexOf问题

ArrayList#indexOf()的实现代码

1
2
3
4
5
6
7
8
9
10
11
12
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}

Object#equals()的实现代码

1
2
3
public boolean equals(Object obj) {
return (this == obj);
}

indexOf检索非null对象时,是通过调用equals方法进行比较,默认的实现方式则是判断引用是否相等。

也就是说,在没有重载equals方式时,默认的检索行为是判断引用是否相等。

重载equals方法后,则是根据equals具体实现进行检索。

因此,当重载equals方式时,需要注意的是这也将影响到列表的检索行为。

四、Finally

~独立小桥风满袖~平林新月人归后~