Picasso image caching - android

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.

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

Android: onBindViewHolder can't cache images

I am trying to download images if they don't exist yet, and keep and re-use them if they've already been downloaded.
While downloading and displaying works, re-using them does not. It seems like mValues isn't the same mValues in different calls.
Here is my code
public void onBindViewHolder(final TabFragment1.SimpleItemRecyclerViewAdapter.ViewHolder holder, int position) {
holder.mItem = mValues.get(position);
holder.mIdView.setText(mValues.get(position).title);
holder.mContentView.setText(mValues.get(position).description);
if (holder.mThumbnail == null) {
System.out.println("thumbnail null"); //NEVER gets called
} else {
if(mValues.get(position).thumbnailData!=null){
System.out.println("thumbnailData contained"); //NEVER GETS CALLED, IT ALWAYS SEEMS TO BE NUL
holder.mThumbnail.setImageDrawable(mValues.get(position).thumbnailData);
} else {
System.out.println("thumbnailData downloading"); //always happening
try {
AsyncTask<String, Void, Bitmap> execute = new DownloadImageTask((ImageView) holder.mThumbnail)
.execute(holder.mItem.thumbnailUrl);
mValues.get(position).thumbnailData = holder.mThumbnail.getDrawable();
if(mValues.get(position).thumbnailData!=null) {
System.out.println("is null"); //hardly ever gets printed
} else {
System.out.println("is not null"); //always gets printed
}
} catch (Exception ex) {
}
}
}
}
SOLVED: my code was wrong. The thumbnail update didn't wait for the AsyncTask to finish and I messed up the if statement so it tricked me into thinking the "new" thumbnail worked. I put the thumbnail update into the AsyncTask and now it's working :)
Your if else statement, inside try catch has interchanged log statements...Here your if statement checks for (thumbnail !=null) but prints it as null if found true.... so my point here is, your thumbnail object is always null, as its value would depend upon completion of Asynctask you started just above it, hence you cannot access it just like that, because this downloading process will run on separate thread.
You could use Picasso library for android, that will cache images and other cool things for you.
You can use any good Image loading library like UIL or Picasso
or Glide.
You can also try setDrawingCacheEnabled(true) on your recycler view.

Image are not displaying from Cache memory using Picasso Library

I am using Picasso library for image download and displaying it in imageView. This library also store images in cache and memory. When my internet is turn on, i am able to view images on imageView. So i think, it should also be store in cache or file memory. Now my internet is turnOFF, but it doest not display to images. kindly have a look.
Picasso.with(context)
.load(url) .placeholder(R.drawable.defaultimg)
.networkPolicy(NetworkPolicy.OFFLINE)
.into(holder.imageview2, new ImageLoadedCallback(holder.loadingBar) {
#Override
public void onSuccess() {
if (holder.loadingBar != null) {
holder.loadingBar.setVisibility(View.GONE);
}
}
#Override
public void onError(){
holder.loadingBar.setVisibility(View.VISIBLE);
Picasso.with(context)
.load(url) .placeholder(R.drawable.defaultimg)
.into(holder.imageview2, new ImageLoadedCallback(holder.loadingBar) {
#Override
public void onSuccess() {
if (holder.loadingBar != null) {
holder.loadingBar.setVisibility(View.GONE);
}
}
#Override
public void onError() {
if (holder.loadingBar != null) {
holder.loadingBar.setVisibility(View.GONE);
}
}
});
}
});
Finally I resolved that issue. Thanks #dev.bmax
image url was not correct. There is bug in Picasso. If we have url like as
https://i.ytimg.com/vi/DMVEcfQmPOs/maxresdefault.jpg?500|700
Picasso is able to displaying image when internet TURN ON
but if we TURN OFF to internet, it does not decode the url. and not display the image also.
We have to remove ?500|700 then i was able to view image in OFFLine mode also.
//url.substring(0,url.indexOf("?"))
https://i.ytimg.com/vi/DMVEcfQmPOs/maxresdefault.jpg
Thanks!

Use a thumbnail as a placeholder for Picasso

From the UX point of view, it will be great to show the user a thumbnail first until the real image completes loading, then showing it to him, but Picasso uses only a resource file as the place holder like:
Picasso.with(context)
.load(url)
.placeholder(R.drawable.user_placeholder)
.into(imageView);
So, how can I use a thumbnail URL as the placeholder? , and if I should use Picasso twice, then how?
An issue is already opened on Picasso's github page with this request, but seems it won't be added to Picasso as per JakeWharton. So how could we do it with what's available in hand?
Thanks to raveN here & the comments on the original request on github, finally I've got a working solution:
Picasso.with(context)
.load(thumb) // thumbnail url goes here
.into(imageView, new Callback() {
#Override
public void onSuccess() {
Picasso.with(context)
.load(url) // image url goes here
.placeholder(imageView.getDrawable())
.into(imageView);
}
#Override
public void onError() {
}
});
The trick here is to get the drawable from the imageView (which is the thumbnail) after the first call & pass it as a placeholder to the second call
-- update --
I've made a blog post describing the whole scenario
You could write a simple helper which calls Picasso twice (as you mentioned).
I've not tested it, but it should go like
Picasso.with(context)
.load(thumbnailUrl)
.error(errorPlaceholderId)
.into(imageView, new Callback() {
#Override
public void onSuccess() {
// TODO Call Picasso once again here
}
#Override
public void onError() {
}
);
There are a couple of different ways to get your Picasso called twice. One method I could think of (again, not tested) is
public static void loadImageWithCallback(String url, Callback callback) {
Picasso.with(context)
.load(url)
.error(errorPlaceholderId)
.into(imageView, callback);
}
public static void loadImage(String url) {
Picasso.with(context)
.load(url)
.error(errorPlaceholderId)
.into(imageView);
}
loadImageWithCallback("http://example.com/mythumbnail.jpg", new Callback() {
#Override
public void onSuccess() {
loadImage("http://example.com/myRealImage.jpg");
}
#Override
public void onError() {
}
}
Edit: All I know is that Picasso provides this callback mechanism. I'm using it in my app to hide a ProgressBar that is displayed until the image is loaded. I'll hide it in success or error callbacks - so you'll have the option to get notified when image loading is done. Then you can simply call it again. I hope the above approach works.
I originally used AbdelHady's solution but found that the larger image is only loaded after the thumbnail is done loading so I came up with this instead.
Assuming you have a utility class in your project;
public final class U {
public static void picassoCombo(final RequestCreator thumbnail,
final RequestCreator large,
final ImageView imageView) {
Target target = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
imageView.setImageBitmap(bitmap);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
imageView.setImageDrawable(errorDrawable);
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
thumbnail.into(imageView);
}
};
imageView.setTag(target); // To prevent target from being garbage collected
large.into(target);
}
}
Usage:
U.picassoCombo(
Picasso.with(context)
.load("http://lorempixel.com/200/100/sports/1/")
.placeholder(R.drawable.ic_image_placeholder),
Picasso.with(context)
.load("http://lorempixel.com/800/400/sports/1/")
.error(R.drawable.ic_image_broken),
imageView
);
In the above example the placeholder is set first, the thumbnail url is set next, and regardless of whether the thumbnail request is done, successful, or failed, the large image request is set once it is done. If the large image request failed, then the error drawable is set.
The only issue is that if you use setIndicatorsEnabled(true) the debug indicators don't show for the large request. As far as I can tell this seems to be by design according to this issue convo

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
}

Categories

Resources