shadowarcher
shadowarcher

Reputation: 3563

Get Bitmap from ImageView loaded with Picasso

I had a method that loads images, if the image has not been loaded before it will look for it on a server. Then it stores it in the apps file system. If it is in the file system it loads that image instead as that is much faster than pulling the images from the server. If you have loaded the image before without closing the app it will be stored in a static dictionary so that it can be reloaded without using up more memory, to avoid out of memory errors.

This all worked fine until I started using the Picasso image loading library. Now I'm loading images into an ImageView but I don't know how to get the Bitmap that is returned so that I can store it in a file or the static dictionary. This has made things more difficult. because it means it tries to load the image from the server every time, which is something I don't want to happen. Is there a way I can get the Bitmap after loading it into the ImageView? Below is my code:

public Drawable loadImageFromWebOperations(String url,
        final String imagePath, ImageView theView, Picasso picasso) {
    try {
        if (Global.couponBitmaps.get(imagePath) != null) {
            scaledHeight = Global.couponBitmaps.get(imagePath).getHeight();
            return new BitmapDrawable(getResources(),
                    Global.couponBitmaps.get(imagePath));
        }
        File f = new File(getBaseContext().getFilesDir().getPath()
                .toString()
                + "/" + imagePath + ".png");

        if (f.exists()) {
            picasso.load(f).into(theView);

This line below was my attempt at retrieving the bitmap it threw a null pointer exception, I assume this is because it takes a while for Picasso to add the image to the ImageView

            Bitmap bitmap = ((BitmapDrawable)theView.getDrawable()).getBitmap();
            Global.couponBitmaps.put(imagePath, bitmap);
            return null;
        } else {
            picasso.load(url).into(theView);
            return null;
        }
    } catch (OutOfMemoryError e) {
        Log.d("Error", "Out of Memory Exception");
        e.printStackTrace();
        return getResources().getDrawable(R.drawable.default1);
    } catch (NullPointerException e) {
        Log.d("Error", "Null Pointer Exception");
        e.printStackTrace();
        return getResources().getDrawable(R.drawable.default1);
    }
}

Any help would be greatly appreciated, thank you!

Upvotes: 10

Views: 33945

Answers (5)

jguerinet
jguerinet

Reputation: 1539

With Picasso you don't need to implement your own static dictionary because it is done automatically for you. @intrepidkarthi was right in the sense that the images are automatically cached by Picasso the first time they are loaded and so it doesn't constantly call the server to get the same image.

That being said, I found myself in a similar situation: I needed to access the bitmap that was downloaded in order to store it somewhere else in my application. For that, I tweaked @Gilad Haimov's answer a bit:

Java, with an older version of Picasso:

Picasso.with(this)
    .load(url)
    .into(new Target() {

        @Override
        public void onBitmapLoaded (final Bitmap bitmap, Picasso.LoadedFrom from) {
            /* Save the bitmap or do something with it here */

            // Set it in the ImageView
            theView.setImageBitmap(bitmap); 
        }

        @Override
        public void onPrepareLoad(Drawable placeHolderDrawable) {}

        @Override
        public void onBitmapFailed(Drawable errorDrawable) {}
});

Kotlin, with version 2.71828 of Picasso:

Picasso.get()
        .load(url)
        .into(object : Target {

            override fun onBitmapLoaded(bitmap: Bitmap, from: Picasso.LoadedFrom) {
                /* Save the bitmap or do something with it here */

                // Set it in the ImageView
                theView.setImageBitmap(bitmap)
            }

            override fun onPrepareLoad(placeHolderDrawable: Drawable?) {}

            override fun onBitmapFailed(e: Exception?, errorDrawable: Drawable?) {}

        })

This gives you access to the loaded bitmap while still loading it asynchronously. You just have to remember to set it in the ImageView as it's no longer automatically done for you.

On a side note, if you're interested in knowing where your image is coming from, you can access that information within that same method. The second argument of the above method, Picasso.LoadedFrom from, is an enum that lets you know from what source the bitmap was loaded from (the three sources being DISK, MEMORY, and NETWORK. (Source). Square Inc. also provides a visual way of seeing where the bitmap was loaded from by using the debug indicators explained here.

Hope this helps !

Upvotes: 44

Thialyson Martins
Thialyson Martins

Reputation: 321

In this example I used to set the background of a colapsing toolbar.

public class MainActivity extends AppCompatActivity {

 CollapsingToolbarLayout colapsingToolbar;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

  colapsingToolbar = (CollapsingToolbarLayout) findViewById(R.id.colapsingToolbar);
  ImageView imageView = new ImageView(this);
  String url ="www.yourimageurl.com"


  Picasso.with(this)
         .load(url)
         .resize(80, 80)
         .centerCrop()
         .into(image);

  colapsingToolbar.setBackground(imageView.getDrawable());

}

I hope it helped you.

Upvotes: 0

Madi
Madi

Reputation: 1855

Use this

Picasso.with(context)
.load(url)
.into(imageView new Callback() {
    @Override
    public void onSuccess() {
        //use your bitmap or something
    }

    @Override
    public void onError() {

    }
});

Hope it help you

Upvotes: -1

Gilad Haimov
Gilad Haimov

Reputation: 5857

Picasso gives you direct control over the downloaded images. To save downloaded images into file do something like this:

Picasso.with(this)
    .load(currentUrl)
    .into(saveFileTarget);

Where:

saveFileTarget = new Target() {
    @Override
    public void onBitmapLoaded (final Bitmap bitmap, Picasso.LoadedFrom from){
        new Thread(new Runnable() {
            @Override
            public void run() {
                File file = new File(Environment.getExternalStorageDirectory().getPath() + "/" + FILEPATH);
                try {
                    file.createNewFile();
                    FileOutputStream ostream = new FileOutputStream(file);
                    bitmap.compress(CompressFormat.JPEG, 75, ostream);
                    ostream.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

Upvotes: 8

njzk2
njzk2

Reputation: 39386

Since you are using Picasso, you may as well want to take full advantage of it. It includes a powerful caching mechanism.

Use picasso.setDebugging(true) on your Picasso instance to view what kind of caching occurs (images are loaded from disk, memory or network). See : http://square.github.io/picasso/ (debug indicators)

The default instance of Picasso is configured with (http://square.github.io/picasso/javadoc/com/squareup/picasso/Picasso.html#with-android.content.Context-)

LRU memory cache of 15% the available application RAM

Disk cache of 2% storage space up to 50MB but no less than 5MB. (Note: this is only available on API 14+ or if you are using a standalone library that provides a disk cache on all API levels like OkHttp)

You can also specify your Cache instance using Picasso.Builder to customize your instance, and you can specify your Downloader for finer control. (There is an implementation of OkDownloader in Picasso which is used automatically if you include OkHttp in your app.)

Upvotes: 0

Related Questions