Let Volley's NetworkImageView show local image files
Asked Answered
P

3

6

I am using NetworkImageView to show some covers downloaded from a remote URL and I successfully manage to cache and show them, but I want to let users set their own cover images if they want. I tried to use setImageUrl method with Uri.fromFile(mCoverFile).toString() as arguments, but it doesn't work. Since it is a mix of remote and local images I can't switch to regular ImageViews, so I was wondering if there's any way to enable loading of local images.

I am of course aware of the ImageView's setImageBitmap method, but NetworkImageView automatically resizes the created Bitmap and also prevents View recycling in GridViews and ListViews.

UPDATE: njzk2's answer did the trick. To autoresize the Bitmap according to your View size, then just copy the ImageRequest.doParse method from Volley's source.

Phyllis answered 17/3, 2014 at 20:32 Comment(0)
B
7

NetworkImageView uses ImageLoader, which in turn uses an ImageCache.

You can provide a custom ImageCache with your images, provided you use the same mechanism for keys:

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

url is not tested before the actual request would be done, so no issue here.

Typically, your 'cache' could look like :

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
    }
}

You use it like :

imageView.setImageUrl(Uri.fromFile(mCoverFile).toString(), new MyCache());

(This has not been actually tested and there may be some adjustments to do)

Bicentenary answered 17/3, 2014 at 20:59 Comment(7)
The problem of this approach, that I already tried, is that I get an error: FileURLConnection cannot be cast to HttpURLConnection.Phyllis
(that being said, the NetworkImageView does simply call setImageBitmap(response.getBitmap()); once the request is done. Once this is done, there is nothing actually preventing the view recycling that I can see)Bicentenary
My approach does not reach the connection opening. If you look closely, you'll see that the cache always hits, and therefore the connection is never opened.Bicentenary
That's because of the structure of the cache key. It starts with the size of the image.Bicentenary
Note that this will decode the bitmap on the UI thread, which is not advisable.Malikamalin
I agree with @goncalossilva's comment, ImageCache's purpose is store bitmaps in the memory so ImageLoader can fetch it fast, finally achieved serve Bitmap without any background thread execution, hence getBitmap() should be doing as light-weight as possible work, if we want to load a bitmap from file system, we should perform a new Request.Concinnity
@VinceStyling: agreed, but there is no way to tell ImageLoader to use a custom ImageRequest, so the new Request would not work for local files (at least at the time of the answer it did not, I have not checked it in a while)Bicentenary
B
1

Thank you for your answer. I wrote some code based on your help.

usage: just use LocalImageCache.class as Cache. No more code to change.

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();
}

}

Bustee answered 24/3, 2017 at 4:31 Comment(0)
V
0

NetworkImageView extends ImageView. You should be able to use the same methods as a regular ImageView

image.setImageResource(R.drawable.my_image);

or

imageView.setImageBitmap(BitmapFactory.decodeFile(imagePath)); 
Violette answered 17/3, 2014 at 20:39 Comment(5)
Read the full question: local files, not drawables. I'd like to take advantage of all NetworkImageView features, bitmap autoresizing, prevention of recycled images in grids/lists and so on.Phyllis
a drawable is a local file, I don't understand?Violette
A Drawable is a resource image inside your /res folder. A local file is a saved jpeg image or one transferred via USB, for example.Phyllis
See my updated answer, you just use the normal route with any old ImageView since NetworkImageView is in fact an ImageViewViolette
You don't use the regular route, because when you use NetworkImageView it also autoresizes the Bitmap so that it takes less memory and using regular imageview methods doesn't prevent view recycling in GridViews and ListViewsPhyllis

© 2022 - 2024 — McMap. All rights reserved.