fal*_*ojr 68 java performance android recycler-adapter android-recyclerview
我基于创建列表和卡片指南创建了RecyclerView示例.我的适配器只有一个模式实现来扩展布局.
问题是滚动性能差.这在RecycleView中只有8个项目.
在一些测试中我验证了在Android L中没有出现这个问题.但在KitKat版本中,性能的下降是显而易见的.
Gal*_*lya 189
我最近遇到了同样的问题,所以这就是我用最新的RecyclerView支持库做的:
使用新的优化ConstraintLayout 替换复杂布局(嵌套视图,RelativeLayout).在Android Studio中激活它:转到SDK Manager - > SDK Tools选项卡 - > Support Repository - >检查ConstraintLayout for Android和Solver for ConstraintLayout.添加到依赖项:
compile 'com.android.support.constraint:constraint-layout:1.0.2'
Run Code Online (Sandbox Code Playgroud)如果可能,使RecyclerView的所有元素具有相同的高度.并添加:
recyclerView.setHasFixedSize(true);
Run Code Online (Sandbox Code Playgroud)使用默认的RecyclerView 绘图缓存方法并根据您的情况进行调整.您不需要第三方库来执行此操作:
recyclerView.setItemViewCacheSize(20);
recyclerView.setDrawingCacheEnabled(true);
recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
Run Code Online (Sandbox Code Playgroud)如果您使用许多图像,请确保它们的大小和压缩是最佳的.缩放图像也可能会影响性能.问题有两个方面 - 使用的源图像和解码的位图.以下示例为您提供了如何解码从Web下载的图像的提示:
InputStream is = (InputStream) url.getContent();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap image = BitmapFactory.decodeStream(is, null, options);
Run Code Online (Sandbox Code Playgroud)最重要的部分是指定inPreferredConfig
- 它定义将为图像的每个像素使用多少字节.请记住,这是首选方案.如果源图像有更多颜色,它仍将使用不同的配置进行解码.
确保onBindViewHolder()尽可能便宜.您可以将OnClickListener设置为一次,onCreateViewHolder()
并通过接口调用适配器外部的侦听器,并传递单击的项目.这样您就不会一直创建额外的对象.在对视图进行任何更改之前,还要检查标志和状态.
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Item item = getItem(getAdapterPosition());
outsideClickListener.onItemClicked(item);
}
});
Run Code Online (Sandbox Code Playgroud)数据更改后,尝试仅更新受影响的项目.例如notifyDataSetChanged()
,在添加/加载更多项目时,不要使整个数据集无效,只需使用:
adapter.notifyItemRangeInserted(rangeStart, rangeEnd);
adapter.notifyItemRemoved(position);
adapter.notifyItemChanged(position);
adapter.notifyItemInserted(position);
Run Code Online (Sandbox Code Playgroud)依靠notifyDataSetChanged()作为最后的手段.
但是,如果您需要使用它,请使用唯一的ID维护您的项目:
adapter.setHasStableIds(true);
Run Code Online (Sandbox Code Playgroud)
RecyclerView将尝试为适配器合成可见的结构更改事件,以便在使用此方法时报告它们具有稳定的ID.这有助于动画和视觉对象持久性的目的,但单个项目视图仍然需要反弹和重新传输.
即使你做的一切都正确,很可能RecyclerView仍然没有你想要的那么顺利.
Sco*_*ggs 11
我发现至少有一种模式可以扼杀你的表现.请记住,经常onBindViewHolder()
调用.因此,您在该代码中执行的任何操作都有可能使您的性能停止.如果您的RecyclerView进行任何自定义,则很容易在此方法中意外地放入一些慢速代码.
我正在根据位置更改每个RecyclerView的背景图像.但加载图像需要一些工作,导致我的RecyclerView缓慢和生涩.
为图像创建缓存创造了奇迹; onBindViewHolder()
现在只需修改对缓存图像的引用,而不是从头开始加载它.现在,RecyclerView拉链了.
我知道不是每个人都会遇到这个问题,所以我不打算加载代码.但请考虑在您的工作中所做的任何工作,onBindViewHolder()
因为它可能会导致RecyclerView性能不佳.
bla*_*vla 10
除了@ Galya的详细答案之外,我想说明即使它可能是一个优化问题,启用调试器也可以减慢很多事情.
如果您要做所有事情来优化您的RecyclerView
并且它仍然无法顺利运行,请尝试将构建变量切换到release
,并检查它在非开发环境中的工作方式(禁用调试器).
在我看来,我的应用程序在debug
构建版本中执行缓慢,但是一旦切换到release
变体,它就能顺利运行.这并不意味着您应该使用release
构建变体进行开发,但很高兴知道无论何时您准备好发布应用程序,它都可以正常工作.
小智 5
我不确定setHasStableId
flag 的用法是否能解决你的问题.根据您提供的信息,您的性能问题可能与内存问题有关.您在用户界面和内存方面的应用程序性能非常相关.
上周我发现我的应用程序泄漏了内存.我发现这是因为在使用我的应用程序20分钟后,我注意到UI的表现非常慢.关闭/打开活动或使用一堆元素滚动RecyclerView非常慢.在使用http://flowup.io/监控我的一些用户后,我发现了这个:
帧时间真的非常高,每秒帧数真的很低.您可以看到某些帧需要大约2秒才能渲染:S.
试图找出导致这个错误的帧时间/ fps的原因我发现我有一个内存问题,你可以在这里看到:
即使平均内存消耗接近15MB,同时应用程序正在丢帧.
这就是我发现UI问题的方式.我的应用程序中有内存泄漏导致大量垃圾收集器事件,这导致了糟糕的UI性能,因为Android VM必须阻止我的应用程序每帧收集内存.
查看代码我在自定义视图中发生了泄漏,因为我没有从Android Choreographer实例中取消注册侦听器.发布修复后,一切正常:)
如果您的应用因内存问题而丢帧,则应查看两个常见错误:
检查您的应用是否在每秒多次调用的方法内分配对象.即使这种分配可以在应用程序变慢的不同位置执行.一个示例可能是在回收器视图视图持有者的onBindViewHolder上的onDraw自定义视图方法内创建对象的新实例.检查您的应用是否将实例注册到Android SDK但未发布.将监听器注册到总线事件中也可能发生泄漏.
免责声明:我一直用来监控我的应用程序的工具正在开发中.我可以访问此工具,因为我是开发人员之一:)如果您想访问此工具,我们很快就会发布测试版!您可以加入我们的网站:http://flowup.io/.
如果您想使用不同的工具,可以使用:traveview,dmtracedump,systrace或集成到Android Studio中的Andorid性能监视器.但请记住,此工具将监控您连接的设备,而不是其他用户设备或Android操作系统安装.
我谈到了RecyclerView
表演.这里有英文幻灯片和俄语录制视频.
它包含一系列技术(其中一些技术已经被@Darya的回答所涵盖).
这是一个简短的总结:
如果Adapter
项目具有固定大小,则设置:
recyclerView.setHasFixedSize(true);
如果数据实体可以用long表示(hashCode()
例如),那么设置:
adapter.hasStableIds(true);
和实现:
// YourAdapter.java
@Override
public long getItemId(int position) {
return items.get(position).hashcode(); //id()
}
在这种情况下Item.id()
不起作用,因为即使Item
内容已经改变它也会保持不变.
PS如果您使用的是DiffUtil,则无需这样做!
使用正确缩放的位图.不要重新发明轮子并使用库.
更多信息如何在这里选择.
始终使用最新版本RecyclerView
.例如,25.1.0
预取中有很大的性能改进.
更多信息在这里.
使用DiffUtill.
DiffUtil是必须的.
官方文件.
简化您的项目布局!
微小的库来丰富TextViews - TextViewRichDrawable
有关详细说明,请参见幻灯片
归档时间: |
|
查看次数: |
46130 次 |
最近记录: |