android画廊视图“口吃"带有延迟图像加载适配器 [英] android gallery view "stutters" with deferred image loading adapter
问题描述
我想创建一个延迟加载适配器以与 Gallery
小部件一起使用.
I would like to create an deferred loading adapter for use with a Gallery
widget.
也就是说getView()
立即返回一个ImageView
,稍后其他的一些机制会异步调用它的setImageBitmap()
方法.我通过创建一个扩展 ImageView
的惰性"ImageView
来做到这一点.
That is to say getView()
returns an ImageView
immediately, and later some other mechanism will asynchronously call its setImageBitmap()
method. I did this by creating a "lazy" ImageView
that extends ImageView
.
public class GalleryImageView extends ImageView {
// ... other stuff here ...
public void setImage(final Looper looper, final int position) {
final Uri uri = looper.get(position);
final String path = looper.sharePath(position);
new Thread(new Runnable() {
@Override
public void run() {
GalleryBitmap gbmp = new GalleryBitmap(context, uri, path);
final Bitmap bmp = gbmp.getBitmap(); // all the work is here
handler.post(new Runnable() {
@Override
public void run() {
if (GalleryImageView.this.getTag().equals(uri)) {
setImageBitmap(bmp);
}
}
});
}
}).start();
}
}
当我在 Gallery
中缓慢滚动时,中心图像不断弹出到中心.确切地说,这很难解释,但这真的很烦人.我也为微调适配器尝试了相同的方法,它在那里完美运行.
When I scroll slowly in the Gallery
, the center image keeps popping into the center. It's hard to explain, exactly, but it's really annoying. I also tried the same approach for a spinner adapter and it works perfectly there.
有什么想法吗?
推荐答案
解决方案是实现一种更智能的方法来确定何时获取缩略图 - 在用户浏览列表时获取缩略图毫无意义.本质上,您希望在 Romain Guy 的 Shelves 应用程序中实现类似的功能.
The solution is to implement a more intelligent method of when to fetch thumbnails - it is pointless fetching thumbnails while the user is flinging through the list. Essentially you want something like that implemented in Romain Guy's Shelves application.
要获得响应速度最快的图库,您需要实现某种形式的内存缓存并执行以下操作:
To get the most responsive Gallery you'll need to implement some form of in-memory cache and do the following:
- 仅当图像存在于您的
getView
的内存缓存中时才设置该图像.设置一个标志,指示是否设置了图像或是否需要下载.您还可以在 SD 卡和内部存储器上的缓存中维护一个内存,如果当前未进行投掷,则显示低分辨率(inSampleSize
设置为 16 或 8)版本,该版本将可见当只是滚动时 - 当用户放手并固定在图像上时,将加载高分辨率版本. - 添加一个
OnItemSelectedListener
(并确保在初始化时调用setCallbackDuringFling(false)
)为所有需要下载的可见项目下载新的缩略图如果用户手指向上(您可以使用getFirstVisiblePosition
和getLastVisiblePosition
来查找可见的视图范围) - 此外,当用户抬起手指时,请检查 1. 自用户放下手指后所选位置是否发生变化,如果发生变化 2. 是否由于您的
OnItemSelectedListener
启动了下载 - 如果它不是然后启动一个.这是为了捕捉没有发生投掷的情况,因此OnItemSelected
永远不会做任何事情,因为在这种情况下它总是在手指向下的情况下被调用.我会使用一个处理程序来延迟你画廊的动画时间开始下载(确保在调用onItemSelected
或当你收到ACTION_DOWN
事件. - 下载图像后,检查是否有任何可见视图请求此图像,然后更新这些视图
- Only set an image if it exists in the in-memory cache from your
getView
. Set a flag indicating whether the image was set or whether a download is required. You could also maintain a memory in a cache on the SD card and internal memory, and if a fling is not currently ongoing then show a low res (inSampleSize
set to 16 or 8) version which will be visible when just scrolling through - the high res version will load when the user lets go and settles on an image. - Add an
OnItemSelectedListener
(and make sure to callsetCallbackDuringFling(false)
when initializing) that downloads new thumbnails for all the visible items that require a download only if the users finger is up (you can usegetFirstVisiblePosition
andgetLastVisiblePosition
to find the range of views visible) - Also when the user lifts their finger check to see 1. if the selected position changed since the user put their finger down and if so 2. whether a download was initiated due to your
OnItemSelectedListener
- if it wasn't then initiate one. This is to catch the case where no flinging occurs, and thusOnItemSelected
never does anything because it is always called with the finger down in this situation. I'd use a Handler to delay starting the downloading by the animation time of your gallery (make sure to clear any delayed messages posted to this handler wheneveronItemSelected
is called or when you get anACTION_DOWN
event. - After an image is downloaded check if any visible views requested this image then and update those views
还要注意,默认的 Gallery 组件没有正确实现视图回收(它假设适配器中的每个位置都有一个独特的视图,并且在这些项目离开屏幕时清除这些项目的回收器,使其变得毫无意义).从更多的角度来看它并不是毫无意义的 - 但它不是下一个/上一个视图的回收器,而是用来避免必须为当前调用 getView
布局更改期间的视图.
Also be aware that the default Gallery component does not properly implement View recycling (it assumes each position in the adapter has a unique view, and also clears the recycler of these items when they go offscreen making it pretty pointless). on more looking it isn't pointless - but it's not a recycler in terms of next/previous views, rather it serves to avoid having to call getView
for the current views during layout changes.
这意味着传递给您的 getView
方法的 convertView
参数通常不会为 null,这意味着您将膨胀很多视图(这很昂贵)- 请参阅我对 是否替代图库的回答与视图回收存在? 一些提示.(PS:我已经修改了该代码 - 我将在布局阶段使用不同的回收站用于布局阶段和滚动阶段,并根据它们的位置检索布局回收站中的视图,如果您从垃圾箱中获得的视图是非空的,因为它将是完全相同的视图;还要在布局阶段之后清除布局回收站——这让事情变得更加快捷)
This means the convertView
parameter passed to your getView
method will more often that not be null, meaning you'll be inflating a lot of views (which is expensive) - see my answer to Does a replacement for Gallery with View recycling exist? for some hints on that. (PS: I have since modified that code - I would use a different recycle bin for layout phases and scroll phases, in the layout phase place and retrieve the views in the layout recycle bin according to their position, and DO NOT call getView if the view you get from the bin is non-null since it will be exactly the same view; also clear the layout recycle bin after the layout phase -- this makes things a bit more snappier)
PS:在OnItemSelected
中做的事情也要非常小心——也就是说,除非它在上面提到的地方,否则尽量少做.例如,我在 OnItemSelected
中的 Gallery 上方的 TextView
中设置了一些文本.将这个调用移动到与我更新缩略图相同的点上,就会产生显着的差异.
PS: Also be very careful with what you do in OnItemSelected
- namely unless it's in the places mentioned above then try to do as little as possible. For instance I was setting some text in a TextView
above my Gallery in OnItemSelected
. Just moving this call into the same points as where I updated thumbnails made a noticable difference.
这篇关于android画廊视图“口吃"带有延迟图像加载适配器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!