5

我想创建一个延迟加载适配器以与Gallery小部件一起使用。

也就是说立即getView()返回一个ImageView,稍后一些其他机制会异步调用它的setImageBitmap()方法。我通过创建一个ImageView扩展的“懒惰”来做到这一点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,中心图像不断弹出到中心。很难准确地解释,但这真的很烦人。我还为微调器适配器尝试了相同的方法,它在那里完美运行。

有任何想法吗?

4

3 回答 3

12

解决方案是实现一种更智能的何时获取缩略图的方法——当用户浏览列表时获取缩略图是毫无意义的。本质上,您希望在 Romain Guy 的Shelves应用程序中实现类似的东西。

要获得响应速度最快的图库,您需要实现某种形式的内存缓存并执行以下操作:

  • 仅当图像存在于您的getView. 设置一个标志,指示是否设置了图像或是否需要下载。您还可以在 SD 卡和内部存储器的缓存中维护一个内存,如果当前没有进行投掷,则显示低分辨率(inSampleSize设置为 16 或 8)版本,该版本在滚动时可见 - 高分辨率当用户放手并选择图像时,将加载版本。
  • 添加一个OnItemSelectedListener(并确保在初始化时调用),仅在用户手指向上时才setCallbackDuringFling(false)为所有需要下载的可见项目下载新缩略图(您可以使用并找到可见的视图范围)getFirstVisiblePositiongetLastVisiblePosition
  • 此外,当用户抬起手指时,请检查 1. 自从用户放下手指后所选位置是否发生变化,如果是 2. 是否由于您的原因启动了下载OnItemSelectedListener- 如果不是,则启动下载。这是为了捕捉没有发生抛掷的情况,因此OnItemSelected从不做任何事情,因为在这种情况下总是用手指向下调用它。我会使用处理程序在您的画廊的动画时间之前延迟开始下载(确保在onItemSelected调用或收到ACTION_DOWN事件时清除发布到此处理程序的任何延迟消息。
  • 下载图像后,检查是否有任何可见视图请求此图像并更新这些视图

另请注意,默认的 Gallery 组件没有正确实现视图回收(它假定适配器中的每个位置都有一个唯一的视图,并且当这些项目离开屏幕时也会清除这些项目的回收器,使其毫无意义)。编辑:更多看它并不是毫无意义的——但就下一个/上一个视图而言,它不是回收器,而是用于避免getView在布局更改期间调用当前视图。

这意味着convertView传递给您的getView方法的参数通常不会为空,这意味着您将夸大很多视图(这很昂贵) - 请参阅我对是否存在具有视图回收的画廊替代品的回答?一些提示。(PS:我已经修改了该代码 - 我将在布局阶段使用不同的回收站进行布局阶段和滚动阶段,并根据它们的位置检索布局回收站中的视图,如果您从 bin 中获得的视图是非空的,因为它将是完全相同的视图;在布局阶段之后还要清除布局回收站——这会让事情变得更快捷)

PS:还要非常小心你所做的事情OnItemSelected- 即除非它在上面提到的地方,否则尽量少做。例如,我在TextView我的画廊上方的OnItemSelected. 只需将此调用移动到与我更新缩略图的相同点就会产生显着差异。

于 2011-05-04T12:32:36.960 回答
12

我有一个答案给你!

当在内部setImage...调用任何方法时ImageView,请求布局传递,例如,setImageBitmap()如上所述定义为

public void setImageBitmap(Bitmap bm) {
    setImageDrawable(new BitmapDrawable(mContext.getResources(), bm));
}

调用

public void setImageDrawable(Drawable drawable) {
    if (mDrawable != drawable) {
        mResource = 0;
        mUri = null;
        updateDrawable(drawable);
        requestLayout(); //layout requested here!
        invalidate();
    }
}

这具有画廊“捕捉”到当前最接近画廊中心的图像中心的效果。

我为防止这种情况所做的就是让加载到画廊中的视图具有明确的高度和宽度(以dips 为单位)并使用ImageView忽略布局请求的子类。这是因为画廊最初仍然有一个布局传递,但每次画廊中的图像发生变化时都不会打扰这样做,我想只有在画廊视图的宽度和高度设置为时才会发生这种情况WRAP_CONTENT,而我们没有。请注意,设置时仍然会在图像invalidate()中调用as 。setImageDrawable()

下面是我非常简单的ImageView子类!

/**
 * This class is useful when loading images (say via a url or file cache) into
 * ImageView that are contained in dynamic views (Gallerys and ListViews for
 * example) The width and height should be set explicitly instead of using
 * wrap_content as any wrapping of content will not be triggered by the image
 * drawable or bitmap being set (which is normal behaviour for an ImageView)
 * 
 */
public class ImageViewNoLayoutRefresh extends ImageView
{
    public ImageViewNoLayoutRefresh(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }

    public ImageViewNoLayoutRefresh(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    public ImageViewNoLayoutRefresh(Context context)
    {
        super(context);
    }

    @Override
    public void requestLayout()
    {
        // do nothing - for this to work well this image view should have its dims
        // set explicitly
    }
}

编辑:我应该提到 onItemSelected 方法也可以工作,但是由于我需要在进行投掷时加入到这一点,所以我想出了上面的方法,我认为这是更灵活的方法

于 2011-07-21T08:29:06.037 回答
2

这可能是 Gallery 的 onLayout 方法中的错误。查看http://code.google.com/p/android/issues/detail?id=16171了解可能的解决方法。

于 2011-05-04T04:49:51.380 回答