RecyclerView.Adapter → ListAdapter
老写法(Java)
java
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private List<Item> items = new ArrayList<>();
public void setData(List<Item> newItems) {
items.clear();
items.addAll(newItems);
notifyDataSetChanged();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_row, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Item item = items.get(position);
holder.tvName.setText(item.getName());
}
@Override
public int getItemCount() {
return items.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
TextView tvName;
ViewHolder(View itemView) {
super(itemView);
tvName = itemView.findViewById(R.id.tv_name);
}
}
}
问题在哪里
notifyDataSetChanged() 会刷新整个列表,没有动画,滚动位置也可能跳动。数据量一大明显卡顿,用户体验差。
新写法(Kotlin + ListAdapter)
kotlin
class MyAdapter : ListAdapter<Item, MyAdapter.ViewHolder>(DiffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_row, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.tvName.text = getItem(position).name
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val tvName: TextView = itemView.findViewById(R.id.tv_name)
}
companion object {
private val DiffCallback = object : DiffUtil.ItemCallback<Item>() {
override fun areItemsTheSame(oldItem: Item, newItem: Item) =
oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: Item, newItem: Item) =
oldItem == newItem
}
}
}
data class Item(val id: Long, val name: String)
数据更新时只需:
kotlin
adapter.submitList(newList)
一句话注意
submitList() 内部在后台线程做 diff 计算,不会卡主线程。但注意不要在高频更新的场景(比如每秒数十次)下反复 new 一个新 list 往里传,容易造成资源浪费。
如果只是列表里某一项的某个字段变了,需要重写 areContentsTheSame,否则 notifyDataSetChanged() 依然需要手动调用。areItemsTheSame 是判断"是不是同一条",通常比 ID;areContentsTheSame 是判断"内容是否变了",通常 equals()。
Java Android 老项目迁移系列,持续更新中。