android RecycleView 局部刷新方式总结

作者 : 开心源码 本文共7354个字,预计阅读时间需要19分钟 发布时间: 2022-05-12 共204人阅读

在5.0以后大家在使用列表控件时已经逐步的使用recycleView来代替ListView了,但是很多人并不理解recycleView的高效率的刷新方式

首先我们先详情一下recycleView自带的刷新方式:

1.使用 Adapter.notifyDataSetChanged();

优点:简单 粗暴 直接刷新所有的Item布局

缺点:(1)刷新的太多了 影响效率 ,假如遇到复杂的逻辑容易卡慢
(2)刷新的时候无法触发 recycleView 的动画

2.自带的局部刷新

Adapter.notifyItemChanged(int)

Adapter.notifyItemInserted(int)

Adapter.notifyItemRangeChanged(int,int)

Adapter.notifyItemRangeInserted(int,int)

Adapter.notifyItemRangeRemoved(int,int)

优点:不用刷新整个列表可以局部刷新 提高效率

缺点: 每次刷新都要知道position 假如刷新单条比较好使 担当刷新条目比较多的时候需要单独计算每个条目的position不是很方便

3.使用DiffUtil android recycleView-24以后自带的比对数据的类

使用方法:
(1)正常创立adapter 注意设置数据是新建一个List 去接受数据

public void setData(List<TextModel> data) {    this.data = new ArrayList<>(data);}

由于在比较的时候需要oldList与新 newList 比较才能得出变化的数据

(2)创立DiffUtil.Callback

public class MyCallback extends DiffUtil.Callback {  private List<TextModel> old_students, new_students;  public MyCallback(List<TextModel> data, List<TextModel> students) {    this.old_students = data;    this.new_students = students;  }  @Override  public int getOldListSize() {    return old_students.size(); }  @Override  public int getNewListSize() {      return new_students.size();  }  // 判断Item能否已经存在  @Override  public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {    return old_students.get(oldItemPosition).getTextTitle() == new_students.get(newItemPosition).getTextTitle();  }// 假如Item已经存在则会调用此方法,判断Item的内容能否一致  @Override  public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {    return old_students.get(oldItemPosition).getTextContent().equals(new_students.get(newItemPosition).getTextContent());  }}

在这里面需要公告 判断Item能否已经存在 条件 和 假如Item已经存在则会调用此方法,判断Item的内容能否一致 条件。

(3)得到比较结果重新设置数据

    DiffUtil.DiffResult result = DiffUtil.calculateDiff(new MyCallback(oldList, mTextModels), true);    myAdapter.setData(mTextModels);    result.dispatchUpdatesTo(myAdapter);

优点:可以自己设置比较两个列表中的数据并刷新

缺点:(1)DiffUtil.calculateDiff()这个方法是执行在主线程的,假如新旧数据List比较大,那么这个方法会阻塞主线程可能出现出现ANR
(2)比较完成后必需调用result.dispatchUpdatesTo(myAdapter)重新设置数据

(4)使用AsyncListDiff android recycleView-27以后自带的比对数据的类
android 在recycleView 的V27包对原来的数据比对类进行了升级 产生的一个新的数据比对类就是 AsyncListDiff

使用方法:

(1)创立adapter并在adapter中自实现DiffUtil.ItemCallback,给出item差异性计算条件

 public class MyItemCallBack extends DiffUtil.ItemCallback<TextModel> {    @Override    public boolean areItemsTheSame(@NonNull TextModel oldItem, @NonNull TextModel newItem) {      return TextUtils.equals(oldItem.getTextTitle(), newItem.getTextTitle());    }    @Override    public boolean areContentsTheSame(@NonNull TextModel oldItem, @NonNull TextModel newItem) {      return TextUtils.equals(oldItem.getTextContent(), newItem.getTextContent());    }}

(2)将所有对数据的操作代理商给AsyncListDiffer,可以看到这个Adapter是没有List数据的

public class MyDiffAdapter  extends RecyclerView.Adapter {  private Context mContext;  private AsyncListDiffer<TextModel> mTextDiffl;  private DiffUtil.ItemCallback<TextModel> diffCallback = new MyItemCallBack();  public MyDiffAdapter(Context mContext) {      this.mContext = mContext;      mTextDiffl = new AsyncListDiffer<>(this, diffCallback);  }  @NonNull  @Override  public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {      View itemView = LayoutInflater.from(mContext).inflate(R.layout.item_view, null);      return new MyViewHolder(itemView);  }  @Override  public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {      MyAdapter.MyViewHolder myViewHolder = (MyAdapter.MyViewHolder) holder;      TextModel textModel = getItem(position);      myViewHolder.tv.setText(textModel.getTextTitle() + "." + textModel.getTextContent());  }  @Override  public int getItemCount() {      return mTextDiffl.getCurrentList().size();  }  public void submitList(List<TextModel> data) {    mTextDiffl.submitList(data);  }  public TextModel getItem(int position) {      return mTextDiffl.getCurrentList().get(position);  }  class MyViewHolder extends RecyclerView.ViewHolder {      TextView tv;      MyViewHolder(View itemView) {          super(itemView);          tv = (TextView) itemView.findViewById(R.id.item_tv);    }  }}

(3)使用submitList()升级数据,并刷新ui

public void change1() {    for(int i = 0; i<10;i++){        TextModel textModel= new TextModel("aa"+i,"bb"+i%3);        mTextModels.add(textModel);    }    myDiffAdapter.submitList(mTextModels);}

比照之前DiffUtil 优点:(1)不用创来那个两个List比较
(2)将比较放在了子线程中 不再中主线程中比较减少刷新造成的卡慢
下面解析一下 AsyncListDiffer的源码

public class AsyncListDiffer<T> {  private final ListUpdateCallback mUpdateCallback;  final AsyncDifferConfig<T> mConfig;  final Executor mMainThreadExecutor;  private static final Executor sMainThreadExecutor = new AsyncListDiffer.MainThreadExecutor();  @Nullable  private List<T> mList;  @NonNull  private List<T> mReadOnlyList;  int mMaxScheduledGeneration;  public AsyncListDiffer(@NonNull Adapter adapter, @NonNull ItemCallback<T> diffCallback) {      this((ListUpdateCallback)(new AdapterListUpdateCallback(adapter)), (AsyncDifferConfig)(new Builder(diffCallback)).build());  }  public AsyncListDiffer(@NonNull ListUpdateCallback listUpdateCallback, @NonNull AsyncDifferConfig<T> config) {      this.mReadOnlyList = Collections.emptyList();      this.mUpdateCallback = listUpdateCallback;      this.mConfig = config;      if (config.getMainThreadExecutor() != null) {          this.mMainThreadExecutor = config.getMainThreadExecutor();      } else {          this.mMainThreadExecutor = sMainThreadExecutor;      }  }  @NonNull  public List<T> getCurrentList() {      return this.mReadOnlyList;  }  public void submitList(@Nullable final List<T> newList) {      // 用于控制计算线程,防止在上一次submitList未完成时,      // 又屡次调用submitList,这里只返回最后一个计算的DiffResult      final int runGeneration = ++this.mMaxScheduledGeneration;      if (newList != this.mList) {          if (newList == null) {              int countRemoved = this.mList.size();              this.mList = null;              this.mReadOnlyList = Collections.emptyList();              this.mUpdateCallback.onRemoved(0, countRemoved);          } else if (this.mList == null) {              this.mList = newList;              this.mReadOnlyList = Collections.unmodifiableList(newList);              this.mUpdateCallback.onInserted(0, newList.size());          } else {              final List<T> oldList = this.mList;              this.mConfig.getBackgroundThreadExecutor().execute(new Runnable() {                  public void run() {                      final DiffResult result = DiffUtil.calculateDiff(new Callback() {                          public int getOldListSize() {                              return oldList.size();                          }                          public int getNewListSize() {                              return newList.size();                          }                          public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {                              T oldItem = oldList.get(oldItemPosition);                              T newItem = newList.get(newItemPosition);                              if (oldItem != null && newItem != null) {                                  return AsyncListDiffer.this.mConfig.getDiffCallback().areItemsTheSame(oldItem, newItem);                              } else {                                  return oldItem == null && newItem == null;                              }                        }                          public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {                              T oldItem = oldList.get(oldItemPosition);                              T newItem = newList.get(newItemPosition);                              if (oldItem != null && newItem != null) {                                  return AsyncListDiffer.this.mConfig.getDiffCallback().areContentsTheSame(oldItem, newItem);                              } else if (oldItem == null && newItem == null) {                                  return true;                              } else {                                  throw new AssertionError();                              }                          }                          @Nullable                          public Object getChangePayload(int oldItemPosition, int newItemPosition) {                              T oldItem = oldList.get(oldItemPosition);                              T newItem = newList.get(newItemPosition);                              if (oldItem != null && newItem != null) {                                  return AsyncListDiffer.this.mConfig.getDiffCallback().getChangePayload(oldItem, newItem);                              } else {                                  throw new AssertionError();                              }                          }                      });                      AsyncListDiffer.this.mMainThreadExecutor.execute(new Runnable() {                          public void run() {                              if (AsyncListDiffer.this.mMaxScheduledGeneration == runGeneration) {                                 AsyncListDiffer.this.latchList(newList, result);                              }                          }                      });                  }              });          }      }  }  void latchList(@NonNull List<T> newList, @NonNull DiffResult diffResult) {      this.mList = newList;      this.mReadOnlyList = Collections.unmodifiableList(newList);      diffResult.dispatchUpdatesTo(this.mUpdateCallback);  }  private static class MainThreadExecutor implements Executor {      final Handler mHandler = new Handler(Looper.getMainLooper());      MainThreadExecutor() {      }      public void execute(@NonNull Runnable command) {          this.mHandler.post(command);      }  }}

他其实就是google自己对DiffUtil进行的一次封装
(1)首先在构造方法中创立线程池进行管理
(2)submitList时候先判断数组的内存地址能否相同
(3)判空
(4)开启子线程使用DiffUtil.calculateDiff进行数据比较
(5)回调

demo github地址: 525642022/localRefresh

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » android RecycleView 局部刷新方式总结

发表回复