Ros*_*mov 5 performance android android-recyclerview
它由用于帖子的外部回收器视图和用于评论的嵌套 RV 组成(屏幕截图上有缩进)。
问题: 主要是在调试模式下,只有在初始滚动发生时才会出现相当大的卡顿(可能是 RV 的一些初始化内容)。进一步滚动在调试和发布中都是平滑的。在发布中,它主要发生在使用一些密集型应用程序之后,例如在 Facebook 应用程序上观看视频。如果它发生在发布中,那么卡顿就不那么明显了。 初始滚动发生时的 Systrace
设置详情
电话 - Nexus 5X 与 Android 8.1,compileSdkVersion - 28,minSdkVersion - 16,targetSdkVersion - 28
相关代码如下:
外部 RV 的适配器- 在这里,我使用带有评论的帖子数据以及嵌套的 RV 池,以便嵌套的 RV 可以利用它。视图持有者只是在视图中存储一些对不同控件的引用。onCreateViewHolder是我尝试一些优化的地方,包括预创建 10 个视图持有者(当前代码)。我已将setHasFixedSize设置为 true,但这没有帮助。RV 的布局管理器是LinearLayoutManager,没有任何自定义。
if (viewHolders.size == 0) {
//Log.w("msg", "creating all view holders")
for (i in 1..10) {
val v = LayoutInflater.from(parent.context)
.inflate(R.layout.wallpost_view, parent, false) as LinearLayout
val viewHolder = MyViewHolder(v, context, nestedViewsPool)
viewHolders.push(viewHolder)
}
}
Run Code Online (Sandbox Code Playgroud)
内部 RV 的适配器- 这里没有什么特别之处,因为它目前不包含任何自定义事件。
外部 RV 项目的视图-是的,它使用嵌套布局,但在将其转换为 ConstraintLayout, CL 版本时,我没有看到任何性能差异。
内部 RV 项目的视图- 这里没有什么特别之处,看起来与外部项目的视图相似,但没有按钮和链接。CL 版本在这里
什么会导致卡顿?自从我最初使用简化的视图和代码进行测试以来,它就一直存在(在调试中)。
需要注意的几件事
1-不在调试模式下测量性能
我怎么强调都不为过。在不附加调试器的情况下运行,您将看到性能的巨大改进。
2-扁平化你的设计
不要使用每个项目都有一个 RV 的 RV,而是使用具有不同单元格的单个 RecyclerView。因此,第一个单元格将是“墙贴内容”,第二个单元格将是“墙贴答案 1”,第三个“墙贴答案 2”等。
我一直在努力让我的一个屏幕表现得更好,其中我们有水平 RV(具体来说是 viewPager 2)和嵌套垂直 RV,我追逐了许多死胡同,最终不得不采取一些技巧,例如禁用预加载上一页/下一页,直到当前页面加载完毕。但在初始加载后它不会挣扎。
3- 进行<include布局不太可能使其变慢。
但是嵌套层次结构确实如此,例如:
<LinearLayout>
<LinearLayout>
<LinearLayout>
Run Code Online (Sandbox Code Playgroud)
考虑将所有内容重写为单个 ConstraintLayout。你的用户界面并没有那么复杂。删除一些东西,对其进行测量,如果明显改善则进行转换。我会从内部布局开始,因为单个屏幕上可能有更多布局?
最后
4-小心日期转换
我注意到 ThreeTenAbp 中的一些方法消耗了不合理的时间。尝试跳过所有这些方法,用虚拟字符串替换它,并检查它是否有任何区别。如果是的话,你有几个选择,但这是我最初的两个怀疑
如果 Java 8 DateTime 也有同样的问题,我不会感到惊讶。
===============
写完以上所有内容后,我查看了您的 systrace。从快速看来,罪魁祸首似乎是嵌套的线性布局。我可以看到大约 1.880 毫秒,有一个很长的膨胀,需要 30 毫秒,这是一个很大的危险信号。它内部有 3 个线性布局,它们往往指向内部或外部布局的大致方向。所以我会先尝试(3),如果还不够,我会尝试(2)。
============== 编辑:添加(5)
5-为内部recyclerview共享一个RecycledViewPool
创建 RecycledViewPool 类型的单个对象并将其分配给所有内部 recyclerview。
https://developer.android.com/reference/androidx/recyclerview/widget/RecyclerView.RecycledViewPool
我会将其作为答案发布,因为它满足了我的要求 - 它减少了第一次滚动所需的时间。
我在调用活动中移动了两种类型的视图持有者的预创建:
for (i in 1..30) {
val v = LayoutInflater.from(parent.context).inflate(R.layout.wallpost_view, parent, false) as LinearLayout
val viewHolder = MyViewHolder(v, context, nestedViewsPool)
viewHolders.push(viewHolder)
}
for (i in 1..20) {
val v = LayoutInflater.from(this).inflate(R.layout.comment_view, null) as LinearLayout
val viewHolder = WallpostsListAdapter.CommentsViewHolder(v)
adapter.commentViewHolders.push(viewHolder)
}
Run Code Online (Sandbox Code Playgroud)
在我进行的大多数测试中,这使得第一次滚动速度加快了 2 倍。这一行动在优化过程中带来了最大的收益。
我也采纳了@Fabio的部分建议:
1.正如我在评论中所说,我在调试模式下测量这些东西,以便能够更好地看到优化结果。当然,在发布版本中,以毫秒为单位的数字会小得多(实际上比我在发布版本的 systrace 中看到的小 10 倍)。
2.这是造成最大差异的一点,虽然差异不大,但仍然可以在 systrace 中发现。检查答案末尾的pastebins以获取更多信息。
3.事实上,Google 建议使用ContraintLayout而不是嵌套布局,但就我而言,这没有任何区别。实际上,嵌套线性布局似乎显示出稍微更好的结果。我的猜测是,视图不够复杂,无法看到 CL 的收益。我无法使用嵌套线性布局测试最终优化的代码,因为我现在使用单个多类型视图 RV 并且它们无法正常工作,无法找到原因,但可能不会获得增益如此重要。
4.好点,但至少对我来说没有任何重大影响。
5.已过时,因为现在只有一个 RV,没有嵌套。
相关代码
系统跟踪