stephanenicolas / robospice

Repo of the Open Source Android library : RoboSpice. RoboSpice is a modular android library that makes writing asynchronous long running tasks easy. It is specialized in network requests, supports caching and offers REST requests out-of-the box using extension modules.
Apache License 2.0
2.95k stars 545 forks source link

Loading an image with different options (dimension, etc) without re-downloading #384

Open fikr4n opened 9 years ago

fikr4n commented 9 years ago

I feel bitmap handling in Robospice is a little strange. As far as I know, SpiceRequest.loadDataFromNetwork is intended only for downloading a resource, parsing it, and returning it, instead of handling caching stuff. However, the BitmapRequest class which is usually used in loadDataFromNetwork needs a cache File. I am confused how to use a BitmapRequest with an InFileBitmapObjectPersister and an LruCacheBitmapObjectPersister which decorate it.

Suppose that I want to use both memory cache and disk cache and I want to get an image with different options. For example, a screen-width-sized image and a circle-shaped avatar-sized image. Because the image is the same, network request is only needed to be executed once, while loading it into memory has to be done differently. Is there any solution or plan to achieve this with Robospice? So far, loading bitmap with options is done in BitmapRequest.

I think that loading the image into memory with scaled-down size and cutting it into a circle has to be done in the memory cache loader (LruCacheBitmapObjectPersister or a subclass of it) and the cache keys are different. For example: cache key for disk cache is "my-image.png" and cache keys for memory cache are "my-image.png/wide" and "my-image.png/avatar".

   request ("my-image.png/avatar")
                  |
                  v
memory cache exists ("my-image.png/avatar")
   |                            |
  YES                           NO
   |                            |
   v                            v
load it        disk cache exists ("my-image.png")
   |             |                           |
   v            YES                          NO
give it          |                           |
                 |              download ("my-image.png")
                 |                           |
                 |                           v
                 |            put disk cache ("my-image.png")
                 |                           |
         load, scale, cut <------------------'
                 |
                 v
put memory cache ("my-image.png/avatar")
                 |
                 v
              give it

Can I achieve this with the current version of Robospice? If not, can someone give me a pointer or approach to achieve this?

stephanenicolas commented 9 years ago

Hi @flikr4n,

You're right. Image handling is different in RS. We had to use one more file in order to cache the data and avoid filling up the RAM with large bitmaps.

The file you provide is just a temp file that wil contain the raw data obtained from the network. The data file in the cache will contain the data after scaling down the image to appropriate dimensions.

I don't think you can achieve other transformations directly via RS. You would have to first download the image, maybe resizing it, then the listener can cut the image. It is also possible to put things in the cache with RS. With a new cache key.

But there is no better way to automate this with current RS.

Thx for all details in your question. On Dec 2, 2014 8:26 AM, "fikr4n" notifications@github.com wrote:

I feel bitmap handling in Robospice is a little strange. As far as I know, SpiceRequest.loadDataFromNetwork is intended only for downloading a resource, parsing it, and returning it, instead of handling caching stuff. However, the BitmapRequest class which is usually used in loadDataFromNetwork needs a cache File. I am confused how to use a BitmapRequest with an InFileBitmapObjectPersister and an LruCacheBitmapObjectPersister which decorate it.

Suppose that I want to use both memory cache and disk cache and I want to get an image with different options. For example, a screen-width-sized image and a circle-shaped avatar-sized image. Because the image is the same, network request is only needed to be executed once, while loading it into memory has to be done differently. Is there any solution or plan to achieve this with Robospice? So far, loading bitmap with options is done in BitmapRequest.

I think that loading the image into memory with scaled-down size and cutting it into a circle has to be done in the memory cache loader ( LruCacheBitmapObjectPersister or a subclass of it) and the cache keys are different. For example: cache key for disk cache is "my-image.png" and cache keys for memory cache are "my-image.png/wide" and "my-image.png/avatar".

request ("my-image.png/avatar") v memory cache exists ("my-image.png/avatar")
YES NO v v load it disk cache exists ("my-image.png")
v YES NO give it download ("my-image.png")
v
put disk cache ("my-image.png")
     load, scale, cut <------------------'
             |
             v

put memory cache ("my-image.png/avatar") | v give it

Can I achieve this with the current version of Robospice? If not, can someone give me a pointer or approach to achieve this?

— Reply to this email directly or view it on GitHub https://github.com/stephanenicolas/robospice/issues/384.

fikr4n commented 9 years ago

@stephanenicolas Thank you for the fast response.

fikr4n commented 9 years ago

Btw, I don't see concurrent image download handling in BitmapRequest. Is concurrent download for the same image handled by RoboSpice (SpiceManager, SpiceService, etc)? I mean, I want to enable concurrent download for different image (and so with JSON request), but avoid it for the same image.

kamikat commented 9 years ago

I've managed to have CacheManager instance exposed to CustomBitmapRequest instance and access cache directly from SpiceRequest. BTW, a cacheFile which is required by BitmapRequest can be obtained directly from CacheManager achieving better encapsulation.

CustomBitmapRequest contains information about the bitmap file url and dimension to be decoded. The CacheManager instance is set to CustomBitmapRequest from SpiceService.addRequest method.

Then, CustomBitmapRequest can obtain a cache file location from CacheManager instance with the cache key of image with no dimension limit.

It's a little tricky obtaining a cache file from CacheManager. With a dummy object persister implements InFileObjectPersister<File>, cache file could be obtained using [CacheManager].loadDataFromCache(File.class, [cache-key-to-full-size-bitmap], DurationInMillis.ALWAYS_RETURNED).

Next, download binary data to the cache file, decode to it's appropriate dimension and complete the request.

I'm sorry I can't provide a full demonstration on this due to some policy restrictions.