How to cache images with Picasso async? - android

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();
}
});

Related

Android picasso check if image url exist before load into imageView [duplicate]

This question already has answers here:
how to make picasso display default image when there is an invalid path
(3 answers)
How can I use a Color as placeholder image with Picasso?
(3 answers)
Closed 4 years ago.
I'm currently working on RecyclerView with data binding implement, to load Image from a list of url (/images/slider/my/myImage.jpg) get from API.
#BindingAdapter("imageUrl")
public static void loadImage(ImageView imageView, String imageUrl){
Picasso.with(imageView.getContext()).load(CommUtils.WEBSITE_LINK + imageUrl).into(imageView);
}
Currently i have the code above in my ListAdapter. The code able to load the image fine when the url is in correct link or exist in server else it will it as blank. Therefore, i want to create a case that will check if the image is exist/is correct link before display.
What i want to achieve is:
if(Image Link exist){
//Load Image, Picasso.with.................
} else {
//Use Dummy Photo, Picasso.with..................
}
[Edit] So now i know i can use the error() function to create another load if the path is not exist. How about when in a case that my API will return two difference format or "url" which could be; with path (/images/slider/my/myImage.jpg) or without path (myImage.jpg)
Therefore in my code i want to do something like
if(websitelink + ImageUrl){ load image }
else(websitelink + path + ImageUrl) { load iamge} //Should this code run under error() from the first case??
Can i perform a checking on the ImageUrl first instead of try to load the image directly and only change when is error
Picasso supports placeholder and error images anyways:
Picasso.get()
.load(url)
.placeholder(R.drawable.user_placeholder)
.error(R.drawable.user_placeholder_error)
.into(imageView);
So, if all you want to archieve, is to show some error image, when loading does not work, that is all you need.
You can use com.squareup.picasso.Callback to listen for response.:
Picasso.with(getContext())
.load(url)
.placeholder(R.drawable.image_name) // Your dummy image...
.into(imageView, new com.squareup.picasso.Callback() {
#Override
public void onSuccess() {
// Image is loaded successfully...
}
#Override
public void onError() {
// Unable to load image, may be due to incorrect URL, no network...
}
});

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

Picasso errors on callback

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;
}

How To download and caching bitmap using Picasso library

I am using the following method
Bitmap bitmap = Picasso.with(ListofCardsActivity.this)
.load(overLayUrl).get();
for downloading and get the image from the web url.
Does this method download the image from the url every time, even if it is downloaded already?
What I want is that once the image is downloaded, then from the next time onwards, I should get the image from the cache, no need to download.
If we have the method like the above requirement. please let me know
Does this method download the image from the url every time, even if it is downloaded already?
Not if it is cached.
The Picasso instance you get back with with() is pre-configured to have a memory cache and a disk cache.
Depending on how much you are downloading, you may run out of cache space. And I would hope that Picasso uses stuff like ETag and If-Modified-Since to re-download the image if the image has changed on the server, though I have not examined their code to see if they do, as that behavior is not documented.
Does this method download the image from the url every time, even if it is downloaded already?
Not if it is cached.
According to the documentation and the source code, Picasso doesn't cache anything when using synchronous get() method.
So here is my solution for loading image synchronously and caching it with Picasso:
File fileImage = new File("/path/to/your/image");
final Bitmap[] bmpRes = new Bitmap[1];
final Semaphore semaphore = new Semaphore(0);
Picasso.with(this).load(fileImage).priority(Picasso.Priority.HIGH).into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
bmpRes[0] = bitmap;
semaphore.release();
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
semaphore.release();
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
if(bmpRes[0] != null) {
Bitmap bmp = bmpRes[0];
//TODO: Whatever you want with the bitmap
} else {
//TODO: Failed to load the image
}

Picasso image caching

I want to download the following image downloading code with Picasso image cache.
DownloadImage downloadImage = new DownloadImage();
downloadImage.execute(advert.getImgUrl());
private class DownloadImage extends AsyncTask<String, Void, Bitmap> {
#Override
protected Bitmap doInBackground(String... arg) {
Bitmap bmp = null;
try {
URL url = new URL(arg[0]);
bmp = BitmapFactory.decodeStream(url.openConnection()
.getInputStream());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
return null;
}
return bmp;
}
#Override
protected void onPostExecute(Bitmap result) {
if (result == null) {
Intent intent = new Intent(AdvertisingActivity.this,
AdvertisingErrorActivity.class);
intent.putExtra("ad-error", "Error downloading image");
}
adImg.setImageBitmap(result);
super.onPostExecute(result);
}
}
I have several questions regarding this.
I want to download more than one image in parallel. If I make repeated calls of Picasso.with(getActivity()).load(url); with different url values, does this get done?
I want to download images in one activity and use it in another activity. Is this possible? How can this be done?
If I call Picasso.with(getActivity()).load(url); more than once with the same url value, does this load the cached images for subsequent calls after the image has been downloaded?
If the image download process does not succeed for some reasons, can you make Picasso report you of the failure?
I've researched some more into your questions and decided that I should publish this as an answer rather than a comment.
Yes - Picasso loads images asynchronously so making repeated calls will cause images to be downloaded in parallel.
Yes - just make the call as normal and Picasso will handle the re-use of downloaded images e.g. in Activity1, call Picasso.with(this).load("image1"); and, later, make a call to the same URL in Activity2. The image will already be cached (either in memory or on device storage) and Picasso will re-use it, rather than downloading it again.
Yes - see above (Picasso will automatically use cached images where available)
This does not seem to have such a clear-cut answer. One thing you can do is provide an image to display if an error occurs while fetching the real image:
Picasso.with(context)
.load(url)
.placeholder(R.drawable.user_placeholder)
.error(R.drawable.user_placeholder_error)
.into(imageView);
The 'placeholder' will be displayed whilst the attempt is being made to fetch the image from the web; the 'error' image will be displayed, for instance, if the URL is not valid or if there is no Internet connection.
Update, 17/03/2014:
Picasso supports the use of a callback to report you of a failure. Modify your usual call (e.g. the above example) like so:
.into(imageView, new Callback() {
#Override
public void onSuccess() {
// TODO Auto-generated method stub
}
#Override
public void onError() {
// TODO Auto-generated method stub
}
});
In conclusion, it sounds like Picasso would be a great choice of library for you. It definitely makes image downloading very quick and very easy, so I like it a lot.

Categories

Resources