Picasso doesn't load image on first call ever - java

I have come across a very interisting issue. I am using the bellow code to load bitmaps using picasso:
final Target target = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
// loaded bitmap is here (bitmap)
Log.i(TAG, "bitmapLoaded");
imageView.setImageBitmap(bitmap);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
Log.i(TAG, "bitmapFailed");
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
imageView.setTag(target);
Picasso.with(this)
.load(photoUrl)
.into(target);
I know a lot of questions have being asked about picasso not loading images due to weak reference but I don't think that's the case, since I have followed the solutions suggested in many topics to reference target like above.
In my program, I use this same code in 3 different classes and in 3 distinct moments. What I have noticed is that whenever I call this method for the first time it doesn't work, but for the next times it works, doesn't matter which of the 3 calls is being used. I can say that because I print different messages to the log from this 3 different methods.
Any thoughts about what is going on or have I missed something?
Thank you in advance.

Try to achieve this with using async approach.
Picasso.with(context).load(URL).into(profile, new Callback() {
#Override
public void onSuccess() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {//Use your "bitmap" here
Bitmap innerBitmap = ((BitmapDrawable) profile.getDrawable()).getBitmap();
}
}, 100);
}
Also you may try to use Glide https://github.com/bumptech/glide

Problem: The problem is Picasso holds a weak reference to the target class and it got GARBAGE COLLECTED.
Solution: Convert it to class field instead of using it as local reference.

Related

Get Bitmap using a Target in Picasso

I'm working on movies Android app which get list of movies from an API which provides a poster path for all movies.
I want to get the image as Bitmap from the image's URL to save it as a Bitmap variable in the model class. I want to save the image as blob in the DB to retrieve it directly without redownloading it each time the user opens the app. Is that possible?
I want to do something like this, but it always returns null.
private Bitmap posterBitmap;
public void setPosterBitmap () {
Picasso.get().load(POSTERS_URL).into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
posterBitmap = bitmap; // I don't want to set it to an Image view here
}
#Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {}
});
}
Thanks in advance.
new Thread(() -> {
try {
Bitmap mBitmap = Picasso.get().load(link).get();
} catch (Exception e) {
Log.e(""+e);
}
}).start();
By using
implementation 'com.squareup.picasso:picasso:2.71828'
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...

Load online images in <img> tag with itext

I'm using XMLWorker in itextpdf library to convert xHTML to pdf.
In the xHTML content there is some tag with local storage images and images from the Internet.
Eg:
<img src="https://www.w3schools.com/images/w3schools_green.jpg" alt="W3Schools.com" style="width:104px;height:142px;"/>
With the local images, I have implemented ImageProvider to provide the resource root path.
But with these images from the Internet, it cannot be loaded.
I tried to override Image retrieve(String src) method of AbstractImageProvider to load images from the Internet, but I got NetworkOnMainThread exception.
I don't know how to use AsyncTask or any other wars to load online images and return it inside Image retrieve(String src).
I've searched in the Internet and people only use ImageProvider with local images. Any ideas for me?
I don't really understand your question without context. This may be fit with your question.
Create a callback inside your ImageProvider. Then every time AsyncTask (or anything that helps you make a request) gives the response, trigger it.
public class ImageProvider {
private OnImageProviderCallback callback;
public ImageProvider(OnImageProviderCallback callback) {
this.callback = callback;
}
public OnImageProviderCallback getCallback() {
return callback;
}
public void setCallback(OnImageProviderCallback callback) {
this.callback = callback;
}
public interface OnImageProviderCallback {
void onRetrievedImage(Image image);
}
public void retrive() {
new AsyncTask<Void, Void, Image>() {
#Override
protected Image doInBackground(Void... voids) {
// request for image here
If(request.success()) {
return request.getImage();
}else{
// Handle error
return null;
}
}
#Override
protected void onPostExecute(Image image) {
super.onPostExecute(image);
callback.onRetrievedImage(image);
}
}.execute();
}
}
Then in your activity , make it done by calling this
new ImageProvider(new ImageProvider.OnImageProviderCallback() {
#Override
public void onRetrievedImage(Image image) {
// do something with your image
}
});
Until now, I tried to wrap the whole process of conversion from HTML to PDF inside a "big" AsyncTask.
It's work for now, but the code is a bit ugly because it cause code coupling and hard to extend later on for supporting other conversion types.

Change bitmap format using glide and BitmapTypeRequest

Don't know how to do this :
How to change the DecodeFormat on a bitmap that I want to use as a Request :
final BitmapTypeRequest<?> request = Glide.with(context)
.load(uri)
.asBitmap(); // here should be .format(DecodeFormat.PREFER_ARGB_8888)
final SimpleTarget target = new SimpleTarget() {
#Override
public void onResourceReady(Object resource, GlideAnimation glideAnimation) {
memCache.put(nameString, resource);
}
};
// Must be executed on main thread
context.runOnUiThread(new Runnable() {
public void run() {
request.into(target);
}
});
Problem is : .format(DecodeFormat.PREFER_ARGB_8888) return a BitmapRequestBuilder and I need a BitmapTypeRequest
EDIT :
This operation works perfectly :
Glide.with(context)
.load(uri)
.asBitmap()
.format(DecodeFormat.PREFER_ARGB_8888)
.into(imageView);
But as you can see I cache the bitmaps so this method is not good for my use case.
Check this guide. You need to add GlideModule which customize the builder, and then apply it trough the manifest.

How to specify multiple fallback images with Picasso?

The Picasso library allows one to load an image easily like:
Picasso.with(context).load(url).into(imageview);
The API also allows to specify an error image. But what can I do if I want the library to first try three or four different URLs before giving up and displaying the error image? Ideally these images would be tried sequentially, falling back to the next one if the previous wasn't loaded.
Natively there's no API for such functionality. But with some clever coded Picasso.Target you can easily achieve such functionality.
I'll add here a quick hack-untested code that should give you a rought idea on what to look for. You'll have to test and maybe fine tune, but that should be pretty OK.
private static final List<MultiFallBackTarget> TARGETS = new ArrayList<MultiFallBackTarget>();
public static class MultiFallBackTarget implements Picasso.Target {
private WeakReference<ImageView> weakImage;
private List<String> fallbacks;
public MultiFallBackTarget(ImageView image){
weakImage = new WeakReference<>(image);
fallbacks = new ArrayList<String>();
TARGETS.add(this);
}
public void addFallback(String fallbackUrl){
fallbacks.add(fallbackUrl);
}
public void onBitmapLoaded(Bitmap bitmap, LoadedFrom from){
removeSelf();
ImageView image = weakImage.get();
if(image == null) return;
image.setImageBitmap(bitmap);
}
public void onBitmapFailed(Drawable errorDrawable){
ImageView image = weakImage.get();
if(image == null) {
removeSelf();
return;
}
if(fallbacks.size() > 0){
String nextUrl = fallbacks.remove(0);
// here you call picasso again
Picasso.with(image.getContext()).load(nextUrl).into(this);
} else {
removeSelf();
}
}
public void onPrepareLoad(Drawable placeHolderDrawable){}
private void removeSelf(){
TARGETS.remove(this);
}
}
Remember that Picasso does not hold strong references to the Target you put inside into(object). That means, internally Picasso uses WeakReference to that.
So that means that you need that self reference in TARGETS to keep reference of all MultiFallBackTarget you create and allow them to self-remove when their job is done.

Best method of implementing Picasso.Builder and onImageLoadFailed function

For the past few days I have been implementing Picasso in my Android project. Initial implementation was easy enough, but now I have run into an issue I cannot seem to resolve and have not found a clear answer to in either the Picasso documentation or other tuturials/stackoverflow questions.
My knowledge of java is sufficient, but Android and more advanced OOP concepts are quite new to me so please bear this in mind.
Initially I implemented Picasso like this in my RecyclerViewAdapter:
public void onBindViewHolder(MyViewHolder viewHolder, int i) {
Picasso.with(viewHolder.image.getContext()).setIndicatorsEnabled(true);
Picasso.with(viewHolder.image.getContext())
.load(new File("imagePath"))
.fit()
.centerCrop()
.into(viewHolder.image);
}
This worked fine, but due to unrelated errors I wished to implement debugging options and looked towards the onError() and onImageLoadFailed() functions. Resulting in the following implementation:
Picasso.Builder builder = new Picasso.Builder(viewHolder.image.getContext());
builder.indicatorsEnabled(true);
builder.loggingEnabled(true);
builder.listener(new Picasso.Listener() {
#Override
public void onImageLoadFailed(Picasso picasso, Uri uri, Exception exception) {
Log.d("TAG", " onImageLoadFailed message");
exception.printStackTrace();
}
});
builder.build().load(new File("imagePath"))
.fit()
.centerCrop()
.into(viewHolder.image, new com.squareup.picasso.Callback() {
#Override
public void onError() {
Log.d("TAG", " onError message");
}
});
However, with this implementation Picasso seemed to never reload images from memory when I scrolled through my Recyclerviewer. Therefore I tried the following:
Picasso picasso = new Picasso.Builder(viewHolder.image.getContext()).listener(new Picasso.Listener() {
#Override
public void onImageLoadFailed(Picasso picasso, Uri uri, Exception exception) {
Log.d("TAG", " onImageLoadFailed message");
exception.printStackTrace();
}
}).build();
picasso.with(viewHolder.image.getContext())
.setIndicatorsEnabled(true);
picasso.with(viewHolder.image.getContext())
.load(new File("imagePath"))
.fit()
.centerCrop()
.into(viewHolder.image, new com.squareup.picasso.Callback() {
#Override
public void onError() {
Log.d("TAG", " onError message");
}
});
This implementation seems to work nicely (although it does seem that some images are loaded in memory much quicker than others, perhaps due to .fit(), my next objective will be to optimize file loading speed).
However I am uncertain if this is the best implementation. I have tried to find the answer in the Picasso documentation and it seems to be related to the creation of new Picasso instances / Picasso being a singelton. However, I am afraid I am too inexperienced to fully understand this and there seem to be no tutorials on this topic.
So my main question is as follows: What is the best way of implementing Picasso in a project/throughout multiple activities? Should I use Picasso.Builder to access the onImageLoadFailed function? And if so, should I use it for every activity or not?
Thank you in advance for your help!

Categories