1

So basically I'd like to access the file/ByteArray of the Image or Gif that was loaded into a SimpleDraweeView. When Fresco downloads an image from a url, I want to save that image in my database for future access (to help reduce data usage) since these images do not change. This way, next time I want to load an image into the SimpleDraweeView I load the local media and no need to download it again from the url.

I tried a couple of approaches after adding a listener to the Fresco.newDraweeControllerBuilder where on the onFinalImageSet I was either:

1- Trying to access the File for the image/gif from the cache used by Fresco to get it's ByteArray, however, I always get a hasKey() = False from the ImagePipelineFactory:

val imageRequest = ImageRequest.fromUri(mediaUrl)
val cacheKey = DefaultCacheKeyFactory.getInstance().getEncodedCacheKey(imageRequest, null)
if(ImagePipelineFactory.getInstance().mainFileCache.hasKey(cacheKey)) {
    val resource = ImagePipelineFactory.getInstance().mainFileCache.getResource(cacheKey) 
    val file = (resource as FileBinaryResource).file
}else if (ImagePipelineFactory.getInstance().smallImageFileCache.hasKey(cacheKey)){
    val resource = ImagePipelineFactory.getInstance().mainFileCache.getResource(cacheKey) 
    val file = (resource as FileBinaryResource).file
}

2- Trying to get the bitmap from the imageInfo (as a CloseableStaticBitmap) or animatable (as a CloseableAnimateImage) however if I want to cast the animatable to that CloseableAnimateImage I get a compilation error "unresolved reference: CloseableAnimateImage". Then the idea was to get the ByteArray from the bitmap and save it. Nevertheless, I really want to get the (1) approach.

Any ideas of how to get the cached file? Thank you in advance!

IIRed-DeathII
  • 1,117
  • 2
  • 15
  • 34

3 Answers3

0

Add a dependency in gradle

implementation 'com.squareup.picasso:picasso:2.71828'

Then where you are showing the images

Picasso.get().load("URL").into(target);

Add a target to Picasso

Target target = new Target() {
      @Override
      public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
            imageView.setBitmap(bitmap)
            //You can do whatever you want to do with bitmap

      }

    @Override
    public void onBitmapFailed(Drawable errorDrawable) {
}

    @Override
    public void onPrepareLoad(Drawable placeHolderDrawable) {
}};
Lakhwinder Singh
  • 6,799
  • 4
  • 25
  • 42
  • I don't think you understood my question. I need to get the file loaded by Picasso (or Glide or inner implementation of SimpleDraweeView or whatever) stored in their cache. I AM able to load the image in the view - that's not the problem. What I want is to access the cached FILE. – IIRed-DeathII Jul 17 '19 at 11:42
  • "I want to save that image in my database for future access". Besides, Picasso will delete the file at some point whenever they decide (due to performance/save memory with non-used images, etc) and hence next time I want to load the image it will have to download it again. Plus other stuff I need to do with the files hence I need the file. – IIRed-DeathII Jul 17 '19 at 11:48
  • Updated the answer, please check – Lakhwinder Singh Jul 17 '19 at 11:58
  • check my comment to Alex's answer. – IIRed-DeathII Jul 17 '19 at 13:08
0

Using Glide:

GlideApp.with(context)
            .load(url)
            .into(new SimpleTarget<Drawable>() {
                @Override
                public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
                    // save image here
                }
            });

Using Picasso:

Target target = new Target() {
      @Override
      public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
            // save image here
      }

    @Override
    public void onBitmapFailed(Drawable errorDrawable) {}

    @Override
    public void onPrepareLoad(Drawable placeHolderDrawable) {}
    };

    Picasso.with(this).load(url).into(target);
Alex
  • 962
  • 4
  • 15
  • Hi! Thanks so much for the answer - they look very promising! Do they work for gifs too? – IIRed-DeathII Jul 17 '19 at 11:56
  • Hi, i am sure that Glide does, i am not sure for Picasso. – Alex Jul 17 '19 at 12:16
  • For some reason in Picasso the onBitmapLoaded is not called. But when I close and open the app, for the same url is get called with Picasso.LoadedFrom.DISK and returning the bitmap. Why isn't the onBitmapLoaded called that first time? FYI onBitmapFailed isn't called either. – IIRed-DeathII Jul 17 '19 at 13:06
  • Yes that can happen, and the explanation for it can be found on: https://stackoverflow.com/questions/24180805/onbitmaploaded-of-target-object-not-called-on-first-load or here https://github.com/square/picasso/issues/352. If you still can't get it to work i will suggest switching to Glide if it's not too much trouble. – Alex Jul 17 '19 at 13:13
0

In the end, until someone can answer how to do this with SimpleDraweeView I decided for the meantime to go for Glide. Picasso is not an option since it doesn't support gifs and that's one of the requirements in my question. Moreover, I want to keep displaying the loaded image in the ImageView hence I don't want to change the into to a custom target.

Hence the solution with Glide would be the following one:

First, we try to find the downloaded media inside my database through tryToGetFromMyDatabase. In case of finding it, we would proceed to simply load the ByteArray with Glide. In case we don't find the media saved in the database, the tryToGetFromMyDatabase will return null and hence we proceed to load the url with Glide and listen to when Glide finishes downloading the media. When it's done, we retrieve the file from Glide's cache and save the ByteArray in my database.

The code for such method would be as follows:

val url: String = "http://myUrl"
val mediaByteArray: ByteArray? = tryToGetMediaFromMyDatabase(url)
val myImageView: ImageView = findViewById(R.id.image_view)

if(mediaByteArray == null){
    //We don't have the media saved in our database se we download from url and on response save it in database
    var builder = if(isGif){
            Glide.with(context)
            .asGif()
            .load(mediaUrl)
            .addListener(object: RequestListener<GifDrawable> {
                override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<GifDrawable>?, isFirstResource: Boolean): Boolean {
                    return false
                }

                override fun onResourceReady(resource: GifDrawable?, model: Any?, target: Target<GifDrawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
                    onMediaLoaded(mediaUrl)
                    return false
                }
            })

        }else{
            Glide.with(context)
            .asBitmap()
            .load(mediaUrl)
            .addListener(object: RequestListener<Bitmap>{
                override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Bitmap>?, isFirstResource: Boolean): Boolean {
                    return false
                }

                override fun onResourceReady(resource: Bitmap?, model: Any?, target: Target<Bitmap>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
                    onMediaLoaded(mediaUrl)
                    return false
                }

            })
        }

builder.into(myImageView)

}else{
    //We have the media saved in database so we just load it without downloading it from the url
    var builder = if(isGif){
            Glide.with(context).asGif()
        }else{
            Glide.with(context).asBitmap()
        }
    builder.load(mediaByteArray).into(myImageView)
}

And my onMediaLoaded(url: String) does the following to get the file from Glide cache and save it to my database:

Thread(Runnable {
    val imageBytes = Glide.with(context)
            .asFile()
            .load(url)
            .submit()
            .get()
            .readBytes()
    saveIntoDatabase(url, imageBytes)
})
IIRed-DeathII
  • 1,117
  • 2
  • 15
  • 34