转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/111240529
本文出自【赵彦军的博客】

目录

  • 相关文章
  • recyclerView.setHasFixedSize(true);
  • LinearLayoutManager.setInitialItemPrefetchCount()
  • 局部刷新
  • DiffUtil
  • AsyncListDiff
  • getExtraLayoutSpace
  • 避免创建过多 OnClickListener 对象
  • 复用RecycledViewPool
  • 减少过度绘制

相关文章

https://blog.csdn.net/smileiam/article/details/88396546

https://zhuanlan.zhihu.com/p/49338922

https://www.jianshu.com/p/29352def27e6

SetHasStableIds(true) + getItemId 探究

https://www.jianshu.com/p/66d0feab2b5b

Android AsyncListDiffer-RecyclerView最好的伙伴

recyclerView.setHasFixedSize(true);

当Item的高度如是固定的,设置这个属性为true可以提高性能,尤其是当RecyclerView有条目插入、删除时性能提升更明显。

RecyclerView在条目数量改变,会重新测量、布局各个item,如果设置了 setHasFixedSize(true),由于item的宽高都是固定的,adapter的内容改变时,RecyclerView不会整个布局都重绘。具体可用以下伪代码表示:

void onItemsInsertedOrRemoved() {if (hasFixedSize) layoutChildren();else requestLayout();

LinearLayoutManager.setInitialItemPrefetchCount()

RecyclerView 嵌套 RecyclerView 实现横向滑动,设置 LinearLayoutManager.setInitialItemPrefetchCount() 设置 横向 滚动布局预加载个数,避免UI 卡顿

  • 只有 LinearLayoutManager 有这个api,其他 LayoutManager 没有
  • 只有 RecyclerView 嵌套 RecyclerView 才有效

局部刷新

notifyItemChanged(int position)
notifyItemInserted(int position)
notifyItemRemoved(int position)
notifyItemMoved(int fromPosition, int toPosition)
notifyItemRangeChanged(int positionStart, int itemCount)
notifyItemRangeInserted(int positionStart, int itemCount)
notifyItemRangeRemoved(int positionStart, int itemCount)

DiffUtil

https://blog.csdn.net/zxt0601/article/details/52562770

DiffUtil.Callback 是一个抽象类

    public abstract static class Callback {public abstract int getOldListSize();//老数据集sizepublic abstract int getNewListSize();//新数据集sizepublic abstract boolean areItemsTheSame(int oldItemPosition, int newItemPosition);//新老数据集在同一个postion的Item是否是一个对象?(可能内容不同,如果这里返回true,会调用下面的方法)public abstract boolean areContentsTheSame(int oldItemPosition, int newItemPosition);//这个方法仅仅是上面方法返回ture才会调用,我的理解是只有notifyItemRangeChanged()才会调用,判断item的内容是否有变化//该方法在DiffUtil高级用法中用到 ,暂且不提@Nullablepublic Object getChangePayload(int oldItemPosition, int newItemPosition) {return null;}}

1、继承自DiffUtil.Callback的类,实现它的四个abstract方法

/*** 介绍:核心类 用来判断 新旧Item是否相等* 作者:zhangxutong* 邮箱:zhangxutong@imcoming.com* 时间: 2016/9/12.*/public class DiffCallBack extends DiffUtil.Callback {private List<TestBean> mOldDatas, mNewDatas;//看名字public DiffCallBack(List<TestBean> mOldDatas, List<TestBean> mNewDatas) {this.mOldDatas = mOldDatas;this.mNewDatas = mNewDatas;}//老数据集size@Overridepublic int getOldListSize() {return mOldDatas != null ? mOldDatas.size() : 0;}//新数据集size@Overridepublic int getNewListSize() {return mNewDatas != null ? mNewDatas.size() : 0;}/*** Called by the DiffUtil to decide whether two object represent the same Item.* 被DiffUtil调用,用来判断 两个对象是否是相同的Item。* For example, if your items have unique ids, this method should check their id equality.* 例如,如果你的Item有唯一的id字段,这个方法就 判断id是否相等。* 本例判断name字段是否一致** @param oldItemPosition The position of the item in the old list* @param newItemPosition The position of the item in the new list* @return True if the two items represent the same object or false if they are different.*/@Overridepublic boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {return mOldDatas.get(oldItemPosition).getName().equals(mNewDatas.get(newItemPosition).getName());}/*** Called by the DiffUtil when it wants to check whether two items have the same data.* 被DiffUtil调用,用来检查 两个item是否含有相同的数据* DiffUtil uses this information to detect if the contents of an item has changed.* DiffUtil用返回的信息(true false)来检测当前item的内容是否发生了变化* DiffUtil uses this method to check equality instead of {@link Object#equals(Object)}* DiffUtil 用这个方法替代equals方法去检查是否相等。* so that you can change its behavior depending on your UI.* 所以你可以根据你的UI去改变它的返回值* For example, if you are using DiffUtil with a* {@link android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter}, you should* return whether the items' visual representations are the same.* 例如,如果你用RecyclerView.Adapter 配合DiffUtil使用,你需要返回Item的视觉表现是否相同。* This method is called only if {@link #areItemsTheSame(int, int)} returns* {@code true} for these items.* 这个方法仅仅在areItemsTheSame()返回true时,才调用。* @param oldItemPosition The position of the item in the old list* @param newItemPosition The position of the item in the new list which replaces the*                        oldItem* @return True if the contents of the items are the same or false if they are different.*/@Overridepublic boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {TestBean beanOld = mOldDatas.get(oldItemPosition);TestBean beanNew = mNewDatas.get(newItemPosition);if (!beanOld.getDesc().equals(beanNew.getDesc())) {return false;//如果有内容不同,就返回false}if (beanOld.getPic() != beanNew.getPic()) {return false;//如果有内容不同,就返回false}return true; //默认两个data内容是相同的}

梳理流程图如下

2、使用方法

注释掉你以前写的notifyDatasetChanged()方法吧

在将newDatas 设置给Adapter之前,先调用DiffUtil.calculateDiff()方法,计算出新老数据集转化的最小更新集,就是DiffUtil.DiffResult对象。

//第一个参数是DiffUtil.Callback对象,
//第二个参数代表是否检测Item的移动,改为false算法效率更高,按需设置,我们这里是true。
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffCallBack(mDatas, newDatas), true);

3、DiffUtil.DiffResult 对象的 dispatchUpdatesTo()方法,传入RecyclerView的Adapter,替代原来的mAdapter.notifyDataSetChanged()方法。

diffResult.dispatchUpdatesTo(mAdapter);

AsyncListDiff

public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserViewHodler> {private AsyncListDiffer<User> mDiffer;private DiffUtil.ItemCallback<User> diffCallback = new DiffUtil.ItemCallback<User>() {@Overridepublic boolean areItemsTheSame(User oldItem, User newItem) {return TextUtils.equals(oldItem.getId(), newItem.getId());}@Overridepublic boolean areContentsTheSame(User oldItem, User newItem) {return oldItem.getAge() == newItem.getAge();}};public UserAdapter() {mDiffer = new AsyncListDiffer<>(this, diffCallback);}@Overridepublic int getItemCount() {return mDiffer.getCurrentList().size();}public void submitList(List<User> data) {mDiffer.submitList(data);}public User getItem(int position) {return mDiffer.getCurrentList().get(position);}@NonNull@Overridepublic UserAdapter.UserViewHodler onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_user_list, parent, false);return new UserViewHodler(itemView);}@Overridepublic void onBindViewHolder(@NonNull UserAdapter.UserViewHodler holder, int position) {holder.setData(getItem(position));}class UserViewHodler extends RecyclerView.ViewHolder {//此处省略一段public UserViewHodler(View itemView) {super(itemView);}public void setData(User data) {tvName.setText(data.getName());tvAge.setText(String.valueOf(data.getAge()));}}
}

使用方法:

List<User> users = new ArrayList<>();
for (int i = 0; i < 10; i++) {users.add(new User(String.valueOf(i), "用户" + i, i + 20));
}
mAdapter.submitList(users);

getExtraLayoutSpace

在RecyclerView的元素比较高,一屏只能显示一个元素的时候,第一次滑动到第二个元素会卡顿。

RecyclerView (以及其他基于adapter的view,比如ListView、GridView等)使用了缓存机制重用子 view(即系统只将屏幕可见范围之内的元素保存在内存中,在滚动的时候不断的重用这些内存中已经存在的view,而不是新建view)。

这个机制会导致一个问题,启动应用之后,在屏幕可见范围内,如果只有一张卡片可见,当滚动的时 候,RecyclerView找不到可以重用的view了,它将创建一个新的,因此在滑动到第二个feed的时候就会有一定的延时,但是第二个feed之 后的滚动是流畅的,因为这个时候RecyclerView已经有能重用的view了。

如何解决这个问题呢,其实只需重写getExtraLayoutSpace()方法。根据官方文档的描述 getExtraLayoutSpace将返回LayoutManager应该预留的额外空间(显示范围之外,应该额外缓存的空间)。

LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this) {@Overrideprotected int getExtraLayoutSpace(RecyclerView.State state) {return 300;}
};

避免创建过多 OnClickListener 对象

onCreateViewHolder 和 onBindViewHolder 对时间都比较敏感,尽量避免繁琐的操作和循环创建对象。例如创建 OnClickListener,可以全局创建一个。

同时onBindViewHolder调用次数会多于onCreateViewHolder的次数,如从RecyclerViewPool缓存池中取到的View都需要重新bindView,所以我们可以把监听放到CreateView中进行。

优化前:

@Override
public void onBindViewHolder(ViewHolder holder, int position) {holder.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//do something}});
}

优化后:

private class XXXHolder extends RecyclerView.ViewHolder {private EditText mEt;EditHolder(View itemView) {super(itemView);mEt = (EditText) itemView;mEt.setOnClickListener(mOnClickListener);}}private View.OnClickListener mOnClickListener = new View.OnClickListener() {@Overridepublic void onClick(View v) {//do something}
}

复用RecycledViewPool

在TabLayout+ViewPager+RecyclerView的场景中,当多个RecyclerView有相同的item布局结构时,多个RecyclerView共用一个RecycledViewPool可以避免创建ViewHolder的开销,避免GC。RecycledViewPool对象可通过RecyclerView对象获取,也可以自己实现。

RecycledViewPool mPool = mRecyclerView1.getRecycledViewPool();
//下一个RecyclerView可直接进行setRecycledViewPoolmRecyclerView2.setRecycledViewPool(mPool);mRecyclerView3.setRecycledViewPool(mPool);

减少过度绘制

减少布局层级

Android RecyclerView 性能优化总结相关推荐

  1. Android APP性能优化

    转载自:https://www.cnblogs.com/qwangxiao/p/8727229.html Android APP性能优化(最新总结) 导语 安卓大军浩浩荡荡,发展已近十个年头,技术优化 ...

  2. Android WebView 性能优化

    原文出处:http://motalks.cn/2016/09/11/Android-WebView-JavaScript-3/ WebView相关阅读 Android WebView 和 javaSc ...

  3. Android APP性能优化(一)

    Android APP性能优化(最新总结) 安卓大军浩浩荡荡,发展已近十个年头,技术优化日异月新,如今Android 8.0 Oreo 都发布了,Android系统性能已经非常流畅了.但是,到了各大厂 ...

  4. android 应用性能优化1

    1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾.不想写的原因是随便上网一搜一堆关于性能的建议,感觉大家你一总结.我一总结的都说到了很多优化注意事项,但是看过这些文章后大多数存在一个问题就是只 ...

  5. Android应用性能优化之优化列表头像过度绘制[一]

    为什么80%的码农都做不了架构师?>>>    操作的是否顺畅.卡顿,决定着整体的流畅程度. 事实上android跟iphone的差别,个人觉得很大程度上决定于流畅程度,无论是动画, ...

  6. C语言性能优化书籍,Android应用性能优化 (埃尔韦) 中文PDF扫描版

    <android应用性能优化>主要介绍如何调优android 应用,以使应用更健壮并提高其执行速度.内容包括用java.ndk 优化应用,充分利用内存以使性能最大化,尽最大可能节省电量,何 ...

  7. Android UI性能优化 检测应用中的UI卡顿

    本文已在我的公众号hongyangAndroid首发. 转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/58626355 本文出自 ...

  8. Android的性能优化,全方面给你讲明白

    前言: 作为Android系统的使用者,我们经常会遇到图片加载速度慢.甚至长时间无响应,软件使用不流畅.甚至经常性卡退等问题,这些都是Android开发师需要进一步改进的地方,正是如此,公司对安卓项目 ...

  9. Android客户端性能优化(魅族资深工程师毫无保留奉献)

    Android客户端性能优化(魅族资深工程师毫无保留奉献) 转载学习:http://blog.tingyun.com/web/article/detail/155?from=groupmessage& ...

最新文章

  1. 结构控制Switch Case
  2. 时艳强对话酒儿:gate首发平台币的时机选择
  3. oracle的学习笔记(转)
  4. JavaScript之常用方法讲解
  5. hbuilder的aptana php插件无法提示命名空间之外函数和对象的解决办法
  6. Go底层剖析 | 好书中秋赠送中
  7. android fragment传递参数_fragment之间传值的两种方法
  8. Java多线程售票一张票多买问题
  9. 大学生活的真实写照(经典)
  10. android极光推送使用,极光推送使用实例(二) Android客户端
  11. win10计算机用户删除,Win10删除用户帐户的方法?如何在Win10中删除用户帐户
  12. UIKit基础:6.UIView的常用属性 - SuperView和SubViews基本认识
  13. 海信IP202H-晨星9385芯片-9.0-免拆卡刷固件包
  14. IAP 程序 跳转问题
  15. 四旋翼定高篇之惯导加速度+速度+位置三阶互补融合方案
  16. Extjs——初步学习
  17. 基于JAVA的企业信息员工管理系统的设计与实现(附:源码 论文 sql文件)
  18. 理论学习材料:如何解读小学数学教材
  19. c语言dfs算法初步讲解,[转载]算法初步
  20. vue将数字转成中文大写,一二三四五

热门文章

  1. 大学必须掌握的计算机技巧,大学生必须掌握的电脑办公技巧
  2. mfc打开控制台异常关闭_vc控制台程序关闭事件时的正确处理方式
  3. 分布式内存数据库--Redis事务
  4. Android 使用Listview的优化
  5. 【大数据教程】HDFS基本架构、基本命令、回收站机制和API操作
  6. 六十五、下一个更大的数系列,单调栈解决方法
  7. 2020 年最全 Python 面试题汇总 (一)
  8. 从4篇最新论文详解NLP新范式——Continuous Prompt
  9. 推荐计算机与通信领域SCI期刊,因子稳中看升,对中国作者友好,毕业优选!
  10. 视觉与听觉相结合的深度跨域情绪识别