android RecycleView 局部刷新方式总结
在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 局部刷新方式总结