通过 ContentProvider 和 CursorLoader 的多向 ViewPager 的性能问题

Performance Issue with Multidirectional ViewPager via ContentProvider and CursorLoader

我正在尝试创建一个基于 Activity 的多向寻呼应用程序,该应用程序包含支持 ViewPager,其中包含包含 VerticalViewPagers 的片段。两个 ViewPagers 都使用 FragmentStatePagerAdapter,数据来自通过 CursorLoaders 加载的 ContentProvider。垂直片段仅包含一个简单的 TextView,其中包含水平片段的名称和垂直片段位置。

我遇到的问题是,当您多次水平翻页到末尾并回到开头时,UI 开始滞后。您这样做的次数越多,发生的滞后就越多,最终,您可以从头到尾进行分页,而无需 UI 进行更新,因为它需要很长时间。水平翻页越多,UI 延迟就越严重。

我启用了严格模式以查看 UI 线程上是否有太多工作发生,但事实并非如此。我也试过检查 LeakCanary 是否能找到任何内存泄漏,但它还没有找到。

我刚刚开始通过 Traceview 进行一些跟踪,但是因为我刚刚开始,所以我还没有查明问题所在(我也不太熟悉 Traceview,但正在努力)。

这是 Android 监视器在水平分页一段时间后垂直分页时的样子。您会注意到垂直分页效果很好。

此处看到的尖峰用颜色编码为 VSync 延迟。我还注意到,如果您 运行 应用程序并让它坐在那里,内存将缓慢爬升,直到垃圾收集器为 运行,这会清除一些内存,缓慢爬升将再次继续。

我最初的想法是,要么我做错了加载程序,要么加载程序和嵌套的 ViewPagers 有问题。

我在这里尝试的是不是有什么根本性的错误,或者加载器有什么问题等等?我将继续深入研究这个问题,但与此同时,我希望从其他人那里得到一些关于我的问题可能是什么的想法,或者一些关于如何查明问题的建议。

我创建了一个非常基本的示例应用程序,可以在 https://github.com/hooked82/MultiDirectionalPaging

找到

如果您下拉项目并运行它,在第一次启动应用程序时,您需要单击工具栏中的“+”按钮来填充数据库。

它正在使用来自 https://github.com/castorflex/VerticalViewPager

的 VerticalViewPager

2016 年 8 月 1 日更新 根据 Joe 的回答,原因是在换出 VerticalViewPager 的适配器时膨胀和破坏视图的数量。由于导致适配器无法更新新数据的错误,我无法在我的自定义 FragmentStatePagerAdapter 上实施 swapCursor()。如果我要实现 swapCursor(),我会得到很好的水平分页,但是当 Cursor 收到数据集更改通知时,我的适配器的 UI 不会更新。

我已将 VerticalViewPager 换成自定义 CursorRecyclerView 以获得相同的功能,但仍需要设置 RecyclerView 的正确投放以模仿 VerticalViewPager。

感谢乔的帮助!

问题是发生在水平滚动条上的片段事务数。

1) 在任何view pager中,最多显示3个fragments。对于位置 v1 的垂直方向,有 3 个片段 v0、v1 和 v2。如果您从 v1 滚动到 v2,v0 片段将被销毁并创建 v3 以期待下一次滚动。

因此对于每个垂直滚动最多可能发生两个片段操作。

2) 现在水平存在同样的东西。如果在位置 h1,则创建了片段 h0、h1、h2。现在因为还创建了垂直碎片,每个水平碎片最多有 3 个垂直碎片。现在事情变得有趣了。假设您在每个水平片段中都是 v1,则会发生以下情况(更坏的情况)从 h1 滚动到 h2。首先 h0 被销毁,但 h0 拥有的 v0、v1、v2 frag 也被销毁。然后 h3 与 at min v0/v1 一起创建。但是,如果您之前滚动到 v1,它会记住该位置并创建 v2。

因此,对于每个水平滚动,每次滚动至少有 6 次片段操作,最多 8 次(即成本高达 4 倍)。当您进入视图 inflation/cleanup 时,它会以非常快的速度增长,从而导致您的性能问题。

您最好至少使用回收站视图来处理垂直滚动。您可能需要拦截滚动事件以 "simulate" 视图分页器对部分滚动执行的分页快照。