Use Picasso to Get a Callback with a Bitmap

Use Picasso to get a callback with a Bitmap

Found the answer on github in case anyone is wondering:

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

@Override
public void onBitmapFailed(Drawable errorDrawable) {
}

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

private void someMethod() {
Picasso.with(this).load("url").into(target);
}

@Override
public void onDestroy() { // could be in onPause or onStop
Picasso.with(this).cancelRequest(target);
super.onDestroy();
}

The post recommends not using an anonymous callback, and instead using an instance variable for target.

get bitmap image using picasso library

You can implement your own class implementing the Target interface and then call:

 Picasso.with(context).load("file:///android_asset/DvpvklR.png").into(target);

How to load a Bitmap with Picasso without using an ImageView?

You can create a Target and then modify the Bitmap inside the Targets callback method onBitmapLoaded(...). Here is how:

// make sure to set Target as strong reference
private Target loadtarget;

public void loadBitmap(String url) {

if (loadtarget == null) loadtarget = new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
// do something with the Bitmap
handleLoadedBitmap(bitmap);
}

@Override
public void onBitmapFailed() {

}
};

Picasso.with(this).load(url).into(loadtarget);
}

public void handleLoadedBitmap(Bitmap b) {
// do something here
}

Get Bitmap using a Target in Picasso

This code is working for me:

...
private static final String TAG = MainActivity.class.getName();
private Target mTarget;
...

mTarget = new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
if (bitmap == null) {
Log.w(TAG, "Null");
} else {
Log.i(TAG, "Worked");
}
}

@Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
Log.w(TAG, "failed");
}

@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
Log.i(TAG, "Prepare");
}
};

// Small image loads without resize
// Picasso.get().load("http://www.theretirementmanifesto.com/wp-content/uploads/2016/08/Yoda-free-clip-art-680x410.jpg").into(mTarget);
// Mega high res out of memory image
Picasso.get().load("https://upload.wikimedia.org/wikipedia/commons" +
"/5/5e/M104_ngc4594_sombrero_galaxy_hi-res.jpg").
resize(100, 100).into(mTarget);

Also I'm assuming that the following line is in the manifest:

<uses-permission android:name="android.permission.INTERNET" />

Using this version of Picasso:

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

Also it may be worth declaring the Target as a member variable due to issues Picaso has arising from 'weak references'. You will have to research this, but I believe it may be unsafe to declare the Target as an anonymous inner class.

Also it may be necessary to call resize(x, y) to prevent an out of memory situation depending on the image sizes and whether you control their source.

UPDATE:

The project won't work as written because it is using an synchronous solution, but you're making an asynchronous call:

holder.moviePosterIV.setImageBitmap(movie.getPosterBitmap());

The code:

public Bitmap getPosterBitmap() {
target = new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
posterBitmap = bitmap;
}

@Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {}

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

It cannot be done like this. In a nut shell, the Target is going to be called in the future when the image has been downloaded. But the code is being written as if the image is ready immediately.

It is a synchronous solution to an asynchronous problem. In synchronous programming we write 1 line after the other then return the result when the data is ready.

If we wrote it synchronously:

  f() {
image = getImage(url) // the program could be blocked here for minutes
return image
}

So instead we do it asynchronously:

  f() {
getImageInTheFuture(url, imageReadyFunc); // call imageReadyFunc when it is finally downloaded
}

imageReadyFunc(image) {
setTheImage();
}

The asynchronous solution prevents the app from blocking, but it is also a real pain because we can no longer use a 'return' statement. Instead we have to break the code up into 2 sections. Code that we can run before the image is available. Code that we can run after the image is available.

But under the hood Picasso is doing all of this work for you. I'd really advise against trying to manage the bitmaps directly. In the bad old days of Android before Picasso, Glide, etc. apps used to routinely crash and run out of memory trying to manage their own bitmaps. It is technically difficult to do without causing memory leaks and running out of memory.

Hope that makes sense...

I want get a bitmap use Picasso but fail

Your problem is that nothing keeps a strong reference to the Target instance so it gets garbage collected.
You can't just call new Target() { ... } because there aren't any strong references to it. You need to store it on a field in a view holder or implement it on a subclass of a view.

See this answer:

https://stackoverflow.com/a/30681395/5476209

this guy explicitly managed garbage collection issue happening in library.



Related Topics



Leave a reply



Submit