android - Android ViewHolder 未正确回收并将位图保留在堆上
问题描述
这里发生了几件事:
- 我尝试使用 Coil / Glide,都遇到同样的问题 -> 我怀疑问题不在于图像加载本身,而在于视图持有者的回收过程
- LeakCanary 没有报告任何内存泄漏
- 我使用 Lru 缓存通过他们的查找键存储联系人照片-> 缓存图像由 Coil / Glide 加载,但仍分配在堆上(同一个图像现在在堆上出现两次)
这是它的外观:
如您所见,我有超过 1000 个位图分配在堆上占用了高达 123MB 的空间,即使我的列表只包含大约 80 个项目并且一次应该只显示大约 10 个。
在这里,您可以看到它在从上到下滚动几次后如何快速填充堆:
这是我的适配器的外观:
class CustomerAdapter(
private val viewLifecycleOwner: LifecycleOwner,
private val listener: CustomerClickListener,
private val context: Context,
private val prefsShared: PrefsShared,
private val imageManager: ImageManager,
) : ListAdapter<Customer..., RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
...
CustomerViewHolderPhoto(
context, <-------------|
viewLifecycleOwner, <--|--- Are these actually the problem?
listener, <------------|
imageManager,
binding
)
}
}
class CustomerViewHolderPhoto(
private val context: Context,
private val viewLifecycleOwner: LifecycleOwner,
private val listener: CustomerAdapter.CustomerClickListener,
private val imageManager: ImageManager,
private val binding: ViewHolderCustomerItemPhotoBinding
) : RecyclerView.ViewHolder(binding.root), Releasable {
fun bind(contact: EntityContactWithCustomerWithPhoneNumbersAndVisits) {
...
itemView.setOnClickListener {
listener.onCustomerClicked(contact)
}
imageManager.loadContactImageIntoImageViewAsync(
lifecycleOwner = viewLifecycleOwner,
imageView = binding.imageViewCustomer,
lookupKey = contact.contact.contactBookLookupKey,
)
}
}
class CustomerFragment : Fragment(), CustomerAdapter.CustomerClickListener {
...
private fun setupCustomerAdapter(): CustomerAdapter {
val viewManager = LinearLayoutManager(activity)
val viewAdapter = CustomerAdapter(
viewLifecycleOwner = viewLifecycleOwner,
listener = this,
context = requireContext(),
prefsShared = prefsShared,
imageManager = imageManager
)
binding.recyclerView.apply {
layoutManager = viewManager
adapter = viewAdapter
}
return viewAdapter
}
}
解决方案
图像清除可以在 onViewRecycled 中完成,fe Glide.with(context).clear(imageView)。另外,在 Glide 的情况下,检查缓存策略并选择您需要的内容会很有用。并且作为尺寸优化,当加载的图像可以更小时,ImageView 将有助于使用 Glide.with(context).load(image).centerInside()...
推荐阅读
- typo3 - TYPO3 8 中的排版日期格式
- apache-spark - 无法批量反序列化具有不同数量项目的 PairRDD
- r - 私人组织中的 R 包 - 如何在组织内安装私人依赖项?
- python - 如何在 Python 的 HeatMap 中指定我自己的标准
- javascript - 使用 javascript jquery 3.5.1 获取所有表格元素的值,包括 td、textarea 或 innerHtml 值
- c - _flushall() 在清除缓冲区时不起作用
- powershell - 从此 sha-1 文件中获取 sha-256
- r - 计算 Tukey 中位数
- sql - 如何使用sql server中的group子句从每个组中获取最新记录
- python - UnboundLocalError:创建构造函数后在成员函数中赋值之前引用的局部变量“温度”?