使用recyclerView时一般用notifyItemChanged(int position)刷新列表某一项,onBindViewHolder(@NonNull VH holder, int position)会被调用,在这里处理ui变化。
当频繁调用(如修改进度百分比)时,该item的onBindViewHolder会被频繁调用,如果还有耗时操作或图片加载,会导致资源浪费或图片闪动。而我们需要的只是修改该item的部分UI,其他操作都是不必要的。
找了下recyclerView的api,确实有部分刷新item的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* Notify any registered observers that the item at <code>position</code> has changed with
* an optional payload object.
*
* <p>This is an item change event, not a structural change event. It indicates that any
* reflection of the data at <code>position</code> is out of date and should be updated.
* The item at <code>position</code> retains the same identity.
* </p>
*
* <p>
* Client can optionally pass a payload for partial change. These payloads will be merged
* and may be passed to adapter's {@link #onBindViewHolder(ViewHolder, int, List)} if the
* item is already represented by a ViewHolder and it will be rebound to the same
* ViewHolder. A notifyItemRangeChanged() with null payload will clear all existing
* payloads on that item and prevent future payload until
* {@link #onBindViewHolder(ViewHolder, int, List)} is called. Adapter should not assume
* that the payload will always be passed to onBindViewHolder(), e.g. when the view is not
* attached, the payload will be simply dropped.
*
* @param position Position of the item that has changed
* @param payload Optional parameter, use null to identify a "full" update
*
* @see #notifyItemRangeChanged(int, int)
*/
public final void notifyItemChanged(int position, @Nullable Object payload) {
mObservable.notifyItemRangeChanged(position, 1, payload);
}

根据以上注释,实现onBindViewHolder(@NonNull VH holder, int position, @NonNull List<Object> payloads)

1
2
3
4
5
6
7
8
public void onBindViewHolder(@NonNull VH holder, int position, @NonNull List<Object> payloads){
if (preloads.isEmpty()){
onBindViewHolder(holder, position);
} else {
// 实现局部刷新逻辑
...
}
}

按以上方法实现刷新item局部UI后,就会发现图片不再闪动了,大功告成!