让Volley的NetworkImageView显示本地图像文件

6
我正在使用NetworkImageView来展示从远程URL下载的一些封面,并且我成功地管理了它们的缓存和展示,但是如果用户想要设置自己的封面图片,我想让他们可以这样做。我试图使用带有Uri.fromFile(mCoverFile).toString()参数的setImageUrl方法,但它不起作用。由于它是远程和本地图像的混合,我不能切换到常规的ImageView,所以我想知道是否有任何方法可以启用加载本地图像。
当然我知道ImageViewsetImageBitmap方法,但是NetworkImageView会自动调整创建的Bitmap大小,并防止在GridViewsListViews中进行View回收。
更新:njzk2的答案解决了问题。为了根据您的View大小自动调整位图大小,只需从Volley的源代码中复制ImageRequest.doParse方法即可。
3个回答

7

NetworkImageView 使用 ImageLoader,而 ImageLoader 又使用了一个 ImageCache

您可以提供自定义的 ImageCache 与您的图像一起使用,只要您使用相同的键机制:

 return new StringBuilder(url.length() + 12).append("#W").append(maxWidth)
            .append("#H").append(maxHeight).append(url).toString();

url在实际请求之前没有被测试,所以这里没有问题。

通常,您的“缓存”可能如下所示:

public class MyCache implements ImageLoader.ImageCache {

    @Override
    public Bitmap getBitmap(String key) {
        if (key.contains("file://")) {
            return BitmapFactory.decodeFile(key.substring(key.indexOf("file://") + 7));
        } else {
            // Here you can add an actual cache
            return null;
        }
    }
    @Override
    public void putBitmap(String key, Bitmap bitmap) {
        // Here you can add an actual cache
    }
}

您可以这样使用它:
imageView.setImageUrl(Uri.fromFile(mCoverFile).toString(), new MyCache());

(这尚未经过实际测试,可能需要进行一些调整)

这种方法的问题是,我已经尝试过了,但出现了一个错误:FileURLConnection无法转换为HttpURLConnection - Vektor88
话虽如此,NetworkImageView在请求完成后只需调用“setImageBitmap(response.getBitmap());”即可。完成此操作后,我实际上没有看到任何阻止视图回收的东西。 - njzk2
我的方法无法到达连接开启。如果你仔细看,你会发现缓存总是命中,因此连接从未打开。 - njzk2
1
这是因为缓存键的结构。它以图像的大小开头。 - njzk2
1
请注意,这将在 UI 线程上解码位图,这并不是一个好的做法。 - goncalossilva
显示剩余3条评论

1

谢谢您的回答。我根据您的帮助编写了一些代码。

用法:只需将LocalImageCache.class用作缓存即可,不需要更改任何其他代码。

private ImageLoader mLocalImageLoader;

mLocalImageLoader = new ImageLoader(mRequestQueue,
            new LocalImageCache(mCtx));

NetworkImageView test = (NetworkImageView) findViewById(R.id.iv_test);  

test.setImageUrl("/storage/emulated/0/DCIM/Philm/2017_03_24_01_.png", MySingleton.getInstance(this.getApplicationContext()).getLocalImageLoader());

public class LocalImageCache extends LruCache<String, Bitmap> implements ImageLoader.ImageCache {

public LocalImageCache(int maxSize) {
    super(maxSize);
}

public LocalImageCache(Context ctx) {
    this(getCacheSize(ctx));
}

@Override
public Bitmap getBitmap(String key) {
    key = key.substring(key.indexOf("/"));
    Bitmap result = get(key);
    Log.d("TAG", key);
    if (result == null) {
        Bitmap temp =  BitmapFactory.decodeFile(key);
        put(key, temp);
        return temp;
    } else {
        return result;
    }
}

@Override
public void putBitmap(String key, Bitmap bitmap) {
    // Here you can add an actual cache
    // Never touch here
}

// 默认屏幕5倍的图片缓存
// Returns a cache size equal to approximately three screens worth of images.
public static int getCacheSize(Context ctx) {
    final DisplayMetrics displayMetrics = ctx.getResources().
            getDisplayMetrics();
    final int screenWidth = displayMetrics.widthPixels;
    final int screenHeight = displayMetrics.heightPixels;
    // 4 bytes per pixel
    final int screenBytes = screenWidth * screenHeight * 4;

    return screenBytes * 5;
}

@Override
protected int sizeOf(String key, Bitmap value) {
    return value.getRowBytes() * value.getHeight();
}

}


0

NetworkImageView扩展了ImageView。您应该能够使用与常规ImageView相同的方法

image.setImageResource(R.drawable.my_image);

或者

imageView.setImageBitmap(BitmapFactory.decodeFile(imagePath)); 

阅读完整问题:本地文件,而非可绘制对象。我想利用所有“NetworkImageView”功能,如位图自动调整大小,在网格/列表中防止重复使用的图像等。 - Vektor88
一个drawable是一个本地文件,我不明白? - MobileMon
Drawable是位于/res文件夹内的资源图像。本地文件是保存的jpeg图像或通过USB传输的图像,例如。 - Vektor88
看看我的更新答案,你只需使用普通的ImageView路线,因为NetworkImageView实际上就是一个ImageView。 - MobileMon
你不使用常规的路线,因为当你使用 NetworkImageView 时,它还会自动调整 Bitmap 的大小,以便占用更少的内存,并且使用常规的 ImageView 方法不能防止在 GridView 和 ListView 中对视图进行回收。 - Vektor88

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接