短篇小说:
我有一个(预缓存)自定义 LinearLayoutManager
、RecyclerView
、自定义 RecyclerView.Adaptor
、自定义 RecyclerView.ViewHolder
设置。我只有一个 viewType 和轻量级绑定(bind)函数。它真的没什么特别的,这就是为什么我希望我不需要发布代码。我也不想混淆所有不相关的代码。
我遇到的问题是,尽管没有未能回收任何 View ,但 onCreateViewHolder 仍然偶尔被调用(在初始行膨胀之后)让我想知道我是否有内存泄漏?你认为是这样吗?为什么?是什么决定我的应用仍然需要创建更多 View 而不是回收?
我将添加一件可能以某种方式考虑的因素。我的行有两种视觉状态(它们展开和折叠),并且似乎在不同状态下更随机地混合行会使问题恶化。
全文:
我注意到我的 RecyclerView
的平滑滚动偶尔会出现问题。使用 android studio 的分析器,我注意到以下几点:
- 我所有的
bindViewHolder
方法都非常快,并且不会阻碍滚动。 OnCreateViewHolder
是导致卡顿的原因。这解释了为什么在第一次滚动时总是有一些卡顿。此外,通货膨胀占用的 CPU 时间百分比高得离谱。- 在使用
ConstraintLayout
构造的项目/行布局中,onMeasure
函数性能不佳,破坏了较弱设备上的滚动性能。 - 通过使用
LinearLayout
构造的项目/行布局,性能得到了显着提高。然而,浏览量的膨胀仍然需要足够长的时间来引起问题。
根据这些信息,我尽可能地简化了行项目的布局,确保使用 LinearLayout
。无论如何,在第一个项目出现在屏幕上后,recyclerview 的项目的呈现不应该导致卡顿,因为一个,行都是相同的,除了绑定(bind)到它们的数据,两个,RecyclerView
应该回收行。所以 onCreateViewHolder
最初应该被调用很多,然后很少再被调用。预缓存呢?我发现这是滚动时需要新的查看器的原因之一。我设置了缓存并创建了一个自定义 LinearLayoutManager
,它覆盖了名为 getExtraLayoutSpace(RecyclerView.State state)
的预缓存(预取?)方法并调整了两者,以便有足够的现有可回收 View 来覆盖滚动期间的请求。我的测试确认在初始滚动后,在转换到滚动状态时不会请求新 View 。
所有这一切,我还有两个问题。其中之一是 onCreateViewHolder
在应用程序的使用过程中经常被调用,这会导致一些问题。我在 onFailedToRecycleView()
中放置了一个 Log.w()
以查看是否有任何 View 未被回收,看起来 View 正在被回收。所以现在我认为存在一些内存泄漏,内存分析器显示调用 onCreateViewHolder
时经常发生内存使用跳跃。
最佳答案
三个问题我贴在哪里,
- 是否因为 Recyclerview 不断创建 Viewholder 而导致内存泄漏?
- 为什么会发生内存泄漏?
- 是什么决定我的应用仍然需要创建更多 View 而不是回收?
我相信我基本上已经找到了 3 个问题中的 2 个或相应潜在问题的解决方案。
Recyclerview
类内部是一个Recycler
类和RecycledViewPool
类。 内部 Recycler
对象是向 RecycledViewPool
对象发出请求以回收可用的分离废料查看器的对象它还没有附加的废料观察器来回收。具体来说,这种对可回收 viewholder 的搜索发生在 Recycler
的 getViewForPosition(int position)
函数中。如果(在此函数内)未找到可回收 View ,则调用 mAdapter.createViewHolder(RecyclerView.this, type)
。这导致 onCreateViewholder
被调用。所以要回答第三个问题,Recycler 正在决定何时调用 onCreateViewholder。
请注意,RecycledViewPool
的工作是维护分离的废料查看器的数组列表(每个 View 类型的数组列表的一维数组)。维护函数包括 clear()
、reset()
和 setMaxScrap(int viewType, int max)
,它们的作用与名称所指示的相同。因此,解决第二个问题的途径是创建一个自定义 RecycledViewPool,指示何时清除或减少剪贴簿,以便我可以跟踪剪贴簿 View 的创建和销毁。至于问题 1,这可以通过使用 setMaxScrap(int viewType, int max)
来解决。此外,在 recyclerview 初始化时,我们可以在池中放置一些额外的 scrapviews 并尝试保持最少数量的 scrapviews 这可能可以通过监听器完成。
关于java - Recyclerview onCreateViewHolder 被调用尽管所有 View 都被回收?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54797862/