Picasso errors on callback - android

I've noticed that occasionally images won't load in my app through picasso and that picasso is in fact erring. I am using two images per list item in a list view. Here's the picasso code:
Picasso.with(DashboardActivity.this).load(status).into(iv_customer_status_pic, new Callback() {
#Override public void onSuccess() {
Log.d("Debug", "Picasso Success");
}
#Override public void onError() {
Log.d("Debug", "Picasso Errored");
}
});
How can I ensure that the images are loaded, I don't want them to error and then make them disappear. Also why does it error? Is there a timeout? I noticed on more powerful devices it happens less.

The reasons why it fails might because of no Internet connection and Invalid Image URL.
With regard to the error handling refer to nPn's answer.

The reason the onError() callback for Picasso.with().load().into(target, callback) exists is because there is no 100% guarantee the load will be successful. For example if you are trying to load from a uri and you don't have an internet connection, the load will not be successful.
You can somehow attempt a re-try (which I think is already built into Picasso), but ultimately, you need to handle the case were the load fails (for whatever reason). One option would be to load a "default" image, like a generic "profile picture" if you were trying to load a specific users profile picture.
If you move the implementation of the callbacks to a separate class , or even the containing class you should be able to retry from the onError() call back. Here is what I am thinking:
class ContainingClass implements Callback.EmptyCallback
private int mRetryAttempts = 0;
#Override
public void onError() {
if (mRetryAttempts < 2) {
mRetryAttempts++;
// try again
} else {
mRetryAttempts = 0;
}
}
#Override
public void onSuccess() {
mRetryAttempts = 0;
}

Related

How to cache images with Picasso async?

At start of my application I have list of imageLinks
List<String> imageLinks = Arrays.asList("http://example.com/1.png",
"http://example.com/2.png",
"http://example.com/3.png"
...
"http://example.com/n.png");
I want to download the images async and in next run of my app without internet connection, I want to display the images with Picasso:
mPicasso.load("http://example.com/1.png").into(imageView)
But when I'm trying to download the image in background (io) thread with rxJava. I want to download it in background (io) thread, because I need to display ProgressDialog while images are downloading and go to another activity when it will be done
for (String imageLink:imageLinks )
mPicasso.load(imageLink).into(new SimpleTarget()
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
Log.e(TAG, "onBitmapLoaded: "+imageLink);
subscriber.onNext(true);
subscriber.onCompleted();
})
the error occurs:
java.lang.IllegalStateException: Method call should happen from the main thread.
at com.squareup.picasso.Utils.checkMain(Utils.java:136)
at com.squareup.picasso.RequestCreator.into(RequestCreator.java:496)
My another idea is to download the images with Retrofit , but how to add downloaded image to Picasso disk cache to display it in next time?
I suppose you could use this
Bitmap bitmap = Picasso.with(this)
.load(productCoverImageURL)
.get();
Use that inside your RxJava async job
Just like the message from the exception you posted says - you need to make your Picasso request on the main thread.
Don't be afraid it won't do the actual image (down)loading on the thread you made a call from.
This is exactly why loading into Picasso's Targets is described as an "asynchronous" way of loading images. You used the word "async" in your very question but I'm afraid you don't fully understand yet what this means.
Found solution Picasso.fetch(Callback)
In my case:
mPicasso.load(imageLink).fetch(new Callback() {
#Override
public void onSuccess() {
Log.e(TAG, "onBitmapLoaded: " + imageLink);
subscriber.onNext(true);
subscriber.onCompleted();
}
#Override
public void onError() {
Log.e(TAG, "onBitmapFailed: " + imageLink);
subscriber.onNext(false);
subscriber.onCompleted();
}
});

How to resume a file download in firebase Storage?

I need to download a big file using firebase storage,
it is possible my user face network interruption through the download and i would like to be able to resume this download task.
FileDownloadTask downloadTask = firebaseStorage.getReferenceFromUrl(url).getFile(localFile);
downloadTask.addOnProgressListener(new OnProgressListener<FileDownloadTask.TaskSnapshot>() {
#Override
public void onProgress(FileDownloadTask.TaskSnapshot taskSnapshot) {
Log.v(TAG, "progress" + taskSnapshot.getBytesTransferred());;
}
});
downloadTask.addOnFailureListener(e -> {
CustomLogger.v(TAG, "downloadTask, on Failed: " + courseId);
deleteFilesAfterError(courseId);
});
downloadTask.addOnPausedListener(taskSnapshot
-> CustomLogger.v(TAG, "downloadTask, on paused: " + courseId));
the two last listener are never called. when i set up the complete listener:
downloadTask.addOnCompleteListener()
my app crashes.
even when i set up :
firebaseStorage.setMaxDownloadRetryTimeMillis(2000);
then switch off my network in the middle of a download, the downloadTask fail listener is not trigger. The task still seems to be "in progress" but there no data are downloaded. The documentation is poor on this feature. how am i supposed to implement it?
the fail listener seems broken
when i add a completeListener it crashes my app
firebaseStorage.setMaxDownloadRetryTimeMillis does not seems to have
any effect
any idea on how to tackle a resume feature for a file download?
When you say you switch off your network in the middle of the download, how are you doing this?
The reason I ask is because if you are leaving the activity temporarily to turn off the network stream then your problem might be an activity lifecycle problem.
If you leave the activity and do not handle this in the onPause(), onStop() and so on then you might experience this sort of behavior.
Other than that, your code looks similar to the docs (and my code that works fine), other than the fact that you didn't 'chain' your methods to add the listeners (shouldn't be a problem).
However, your code that you copied and pasted here is partially folded and does not show whether or not you are overiding the onFailure(Exception e) method, but I assume it is folded up in that arrow.
If you are still working on this, can you post the trace for any errors you're receiving on the crash?
Here is a block of code that works during network failure, just for a reference:
FirebaseStorage storage = FirebaseStorage.getInstance();
StorageReference storageReference = storage.getReferenceFromUrl("gs://your-bucket/");
storageReference.getFile(localFile).addOnSuccessListener(YourActivity.this, new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
#Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
}
}
}).addOnFailureListener(YourActivity.this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
}
}

Access cached images (Picasso)

I'm having a loading screen where I fetch data belonging to the logged in user. Among this data is their profile images (three of them).
What I want to do is to cache the images when I download them with their URL in Loading screen. Then in the next activity I want to access the cached images to display them in that activity. So basically load all images in one activity to be used in another one. This way (I figured) I won't have to make a http request everytime user enters the activity where their profile image is shown. Which gives a better user experience.
So it's the matter of getting the images from cache to screen that I can't work out, cause I think I've loaded them into cache correctly, seen below.
Here's my current method in Loading Activity:
Backendless.Data.of(UserFileMapping.class).find(new AsyncCallback<BackendlessCollection<UserFileMapping>>() {
#Override
public void handleResponse(BackendlessCollection<UserFileMapping> response) {
Iterator<UserFileMapping> iterator = response.getCurrentPage().iterator();
while(iterator.hasNext()){
UserFileMapping fileMapping = iterator.next();
String profile1 = fileMapping.profile_url;
String profile2 = fileMapping.profile_url_2;
String profile3 = fileMapping.profile_url_3;
Picasso.with(getApplicationContext())
.load(profile1)
.fetch(new Callback() {
#Override
public void onSuccess() {
continue_button.setVisibility(View.VISIBLE);
loading_text.setText("Done!");
}
#Override
public void onError() {
//Make toast
}
});
}
}
#Override
public void handleFault(BackendlessFault fault) {
System.out.println("FAULT:" + fault.getCode());
}
});
It's the issue with downloading all three images at once as well, but that isn't as important as the caching question. If you have a good idea on this in addition to the cache issue I would gladly like to hear it too.

Does Picasso library for Android handle image loading while network connectivity is off?

I'm working on an application in which i use Picasso library for image loading in my ViewPager and other ImageViews. So i want to know what happens if network connectivity is off. Does the library handle itself or do i have to check the network connectivity before loading image to views?
My code:
Picasso picasso = Picasso.with(getActivity());
picasso.setDebugging(true);
picasso.load(downloadPath+imgDetailPhoto)
.placeholder(R.drawable.no_image)
.error(android.R.drawable.stat_notify_error)
.into(eventImage, new Callback() {
#Override
public void onSuccess() {
Log.d("Success...", "picasso loaded successfully");
}
#Override
public void onError() {
Log.d("Error...", "picasso load error");
}
});
Using below code Picasso caches images for offline use.
Picasso.with(this)
.load(downloadPath+imgDetailPhoto)
.placeholder(R.drawable.no_image)
.error(android.R.drawable.stat_notify_error)
.networkPolicy(NetworkPolicy.OFFLINE)//use this for offline support
.into(eventImage);
Above code is not worke while removing cache.so Picasso can't find image from cache.If not get image from cache we handle to get image online and display it. We achieve that using below code:
Picasso.with(getActivity())
.load(downloadPath+imgDetailPhoto)
.placeholder(R.drawable.no_image)
.error(android.R.drawable.stat_notify_error)
.networkPolicy(NetworkPolicy.OFFLINE)//user this for offline support
.into(eventImage, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError() {
Picasso.with(getActivity())
.load(downloadPath+imgDetailPhoto)
.placeholder(R.drawable.no_image)
.error(android.R.drawable.stat_notify_error)
.networkPolicy(NetworkPolicy.OFFLINE)//user this for offline support
.into(eventImage, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError() {
//get error if image not loaded
}
});
}
});
Picasso caches images for offline use.
I'm using it in a simple movie app where I display a bunch of movie posters. I can turn on airplane mode and my images are still there. Likewise, if I force close the application while in airplane mode, then open the app again, my images will still load.
Hope this helps.
P.S. check out Glide https://github.com/bumptech/glide. It's faster and has smoother loading than Picasso

Robospice. Retry failed request on demand

I need to implement quite popular template of app behaviour - give opportunity to user to retry failed requests. Right now I catch failed request with SpiceServiceListener, and shows dialog where user can press "Retry" button. Unfortunately, using the same CachedSpiceRequest object with SpiceManager.execute() don't give desired behaviour, because RS removing all request listeners from mapRequestToLaunchToRequestListener if request wasn't successful. So request can work fine, but it will not return any information to my Activity.
Is there easy way (without modifying code of library) to implement this?
Unfortunately looks like there are no abstract solution for situation like this, so I had to add code like this in every request.
getSpiceManager().execute(r, new RequestListener<CountProfiles>() {
#Override
public void onRequestFailure(SpiceException spiceException) {
if (act.getSupportFragmentManager().findFragmentByTag("network_problem") == null) {
NetworkProblemDialogFragm.newInstance(r, this).show(act.getSupportFragmentManager(), "network_problem");
} else {
((NetworkProblemDialogFragm) act.getSupportFragmentManager().findFragmentByTag("network_problem")).setSpiceRequest(r);
((NetworkProblemDialogFragm) act.getSupportFragmentManager().findFragmentByTag("network_problem")).setRequestListener(this);
}
}
#Override
public void onRequestSuccess(CountProfiles countProfiles) {
}
});
NetworkProblemDialogFragm is a DialogFragment with Retry button, on click on this button I re execute failed request, using given RequestListener.
Not very beautiful solution, but looks like there no better one.

Categories

Resources