正如标题所说,我正在使用 BaseAdapter 在 ListView 中显示项目。显然,ListView 会重用 View ,包括 TextView 和 NetworkImageView。
假设可以一次显示 3 个项目,NetworkImageView 将被重新用于索引处的项目:1, 4, 7, ....
根据显示的内容,NetworkImageView 将:
- 从网络请求图像并显示它,
- 显示缓存的位图,
- 或显示本地可绘制资源。
项目 2 和 3 工作正常,但是在场景 1 中,假设我们正在显示来自网络的索引 4 处的项目,并且用户在加载 4 之前滚动到项目 7,并且它是本地资源,我们显示本地资源。然而,我们的网络图像请求现在可能刚刚完成,所以我们最终显示了不正确的图像。
我怎样才能执行正确的(预期的)行为?
最佳答案
@Snicolas 的回答很准确,但缺少一些关于如何实际完成的指示。就这样吧。
总体思路是跟踪每一行正在进行的图像请求。这样,当您遇到回收行时,您可以取消挂起的请求并为与该行相关的新数据启动一个新请求。
实现此目的的一种直接方法是制作请求图像加载时可以返回的 ImageContainer
,它是适配器的 ViewHolder/RowWrapper 的一部分。如果您还没有使用这种模式,您应该这样做。有很多例子,包括一个很好的 I/O 演讲。
一旦您将 ImageContainer
添加到您的 holder,请发出图像请求并存储您返回的容器。有点像这样:
ImageListener listener = ImageLoader.getImageListener(holder.imageview, defaultImageResId, errorImageResId);
holder.mImageContainer = ImageLoader.get(url, listener);
下次回收的行出现在适配器的 getView()
方法中时,您可以从它那里取回您的 holder 并检查它是否设置了 ImageContainer
。以下 3 种情况之一可能适用:
- 没有
ImageContainer
,这意味着您可以发出新的图像请求。 - 有一个
ImageContainer
,它加载的 url 与新行数据的 url 相同。在这种情况下,您无需执行任何操作,因为它已经加载了您需要的图像。 - 有一个
ImageContainer
,但它加载的 url 与新行数据不同。在这种情况下,取消请求并为当前行数据重新请求。
如果您愿意,可以通过让您的BaseAdapter
扩展实现来移动其中的一些逻辑AbsListView.RecyclerListener
(并将适配器设置为 ListView
或 GridView
的回收器监听器)。 onMovedToScrapHeap(View view)
方法在刚刚回收的 View 中传递,这意味着您可以取消其中任何待处理的图像请求。
关于Android Volley - 取消 Base Adapter 中的 NetworkImageView 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18302831/