转自:
使用 Payload 提高 RecyclerView 渲染效率
再说Android RecyclerView局部刷新那个坑
在RecyclerView的源码里,有如下方法:
public void onBindViewHolder(VHholder, int position, List<Object> payloads) {
onBindViewHolder(holder, position);
}
该函数不是abstract的,所以容易被忽视,但是,其中payloads
参数,可以实现RecyclerView的局部刷新.
如果你的RecyclerView的ItemView很复杂,有很多图片,checkBox,等,现在我们想修改某个position出的ItemView内容里的一部分,比如: 修改图片,或者 修改checkBox,
如果调用adapter.notifyItemChanged(2);
或者 adapter.notifyDataSetChanged();
会造成这个ItemView的所有视图内容都重新绑定一次,或者,所有的可见ItemView 都重新执行一遍:
public void onBindViewHolder(@NonNull PayloadVHolder holder, int position) {
...
}
如果ItemView和复杂,那就势必会造成性能损失
所以我们就会有疑问,如何能单独刷新某个ItemView的某个子View???
说明:
将对比如下3个方法的 区别:
* `notifyItemChanged(int position, @Nullable Object payload)`
* `notifyItemChanged(int position)`
* `notifyDataSetChanged()`
代码:
- Adapter
public class PayloadAdapter extends RecyclerView.Adapter<PayloadAdapter.PayloadVHolder> {
private LayoutInflater mInflater;
private List<String> datas;
public PayloadAdapter(Context context, List<String> datas) {
mInflater = LayoutInflater.from(context);
this.datas = datas;
}
@NonNull
@Override
public PayloadVHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Log.d("PayloadAdapter", "onCreateViewHolder");
return new PayloadVHolder(mInflater.inflate(R.layout.payload_item, parent, false));
}
@Override
public void onBindViewHolder(@NonNull PayloadVHolder holder, int position, @NonNull List<Object> payloads) {
Log.d("PayloadAdapter", "onBindViewHolder payload: " + payloads);
if (payloads.isEmpty()) {
onBindViewHolder(holder, position);
} else {
holder.botTv.setText("text update by payload position: " + position);
}
}
@Override
public void onBindViewHolder(@NonNull PayloadVHolder holder, int position) {
Log.d("PayloadAdapter", "onBindViewHolder position: " + position);
holder.topTv.setText("position - " + position + "\n" + datas.get(position));
}
@Override
public int getItemCount() {
return null == datas ? 0 : datas.size();
}
static class PayloadVHolder extends RecyclerView.ViewHolder {
TextView topTv, botTv;
public PayloadVHolder(View itemView) {
super(itemView);
topTv = itemView.findViewById(R.id.payload_top_tv);
botTv = itemView.findViewById(R.id.payload_bot_tv);
}
}
}
- 初始化测试数据
public class PayloadActivity extends AppCompatActivity {
RecyclerView payloadRc;
Button payloadBtn;
Button notifyBtn;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rc_payload);
payloadRc = findViewById(R.id.rc_view);
final List<String> datas = new ArrayList<>(15);
for (int i = 0; i < 15; i++) {
datas.add("data - " + i);
}
final PayloadAdapter adapter = new PayloadAdapter(this, datas);
payloadRc.setLayoutManager(new LinearLayoutManager(this));
payloadRc.setAdapter(adapter);
findViewById(R.id.payloadBtn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
adapter.notifyItemChanged(2, "payload");
}
});
findViewById(R.id.notifyBtn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
adapter.notifyItemChanged(2);
}
});
findViewById(R.id.notifyAllBtn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
datas.clear();
for (int i = 0; i < 15; i++) {
datas.add(" new - data - " + i);
}
Log.d("Payload", "notify all ");
adapter.notifyDataSetChanged();
}
});
}
}
xml
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/rc_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/payloadBtn"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="@layout/payload_item" />
<Button
android:id="@+id/payloadBtn"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="notify 3rd with payload"
android:textAllCaps="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/notifyBtn"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/rc_view"
/>
<Button
android:id="@+id/notifyBtn"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="notify 3rd with payload"
android:textAllCaps="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/notifyAllBtn"
app:layout_constraintStart_toEndOf="@+id/payloadBtn"
app:layout_constraintTop_toBottomOf="@+id/rc_view"
/>
<Button
android:id="@+id/notifyAllBtn"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="notify all with notifyDatasetChange"
android:textAllCaps="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/notifyBtn"
app:layout_constraintTop_toBottomOf="@+id/rc_view"
/>
</android.support.constraint.ConstraintLayout>
操作:
*1 首先: 代开界面,日志如下:
界面如下:
可以看到,第一次初始RecyclerView 分别执行了onCreateViewHolder -> onBindViewHolder(_,_,List<Obj> payload) -> onBindViewHolder(_,_)
这个无可厚非
*2 其次: 调用adapter.notifyItemChanged(2);
,日志如下:
可以看到在 position 2 的ItemView 重新执行了onCreateViewHolder -> onBindViewHolder(_,_,List<Obj> payload) -> onBindViewHolder(_,_)
由于数据没变,界面没有变化,界面如下:
*3 接着,调用adapter.notifyItemChanged(2, "payload");
,日志如下:
界面产生如下变化:
说明: 我们传入了一个String : "payload" 作为payload,然后在Adaptar 的
@Override
public void onBindViewHolder(@NonNull PayloadVHolder holder, int position, @NonNull List<Object> payloads) {
Log.d("PayloadAdapter", "onBindViewHolder payload: " + payloads);
if (payloads.isEmpty()) {
onBindViewHolder(holder, position);
} else {
holder.botTv.setText("text update by payload position: " + position);
}
}
进行处理,就实现了RecyclerView 某个ItemView的局部刷新
*4 最后,检测全体的nofity,调用adapter.notifyDataSetChanged();
,日志如下:
界面产生如下变化:
可以看到,所有的ItemView 都发生了变化,而且所有可见的ItemView 又重新执行了一遍onCreateViewHolder -> onBindViewHolder(_,_,List<Obj> payload) -> onBindViewHolder(_,_)
本篇暂时写到这里ヾ(๑╹◡╹)ノ"