I have an image on my server and I want to display it using Picasso on my Android client.
I want to add a default image when the image is loading on Picasso so I am using Target as follows:
Picasso.with(UserActivity.this).load(imageUri.toString()).transform(new RoundedTransformation(500, 1)).into(
new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
userPic.setImageBitmap(bitmap);
}
#Override
public void onBitmapFailed(Drawable drawable) {
userPic.setImageBitmap(defaultDrawable);
}
#Override
public void onPrepareLoad(Drawable drawable) {
userPic.setImageBitmap(defaultDrawable);
}
});
I want to centerCrop() and fit() this image but it gives me an error and it tells me that I cant use them with Target. Is there anyway to use these features on Picasso? Why don't they allow these two functions with Target?
You don't need to use Target to accomplish your goal.
Side note, I am not certain that you can actually use both fit() and centerCrop() together.
See this example:
Picasso.with(context)
.load(url) // Equivalent of what ends up in onBitmapLoaded
.placeholder(R.drawable.user_placeholder) // Equivalent of what ends up in onPrepareLoad
.error(R.drawable.user_placeholder_error) // Equivalent of what ends up in onBitmapFailed
.centerCrop()
.fit()
.into(imageView);
Try this
Picasso.with(context)
.load(url)
.resize(50, 50)
.centerCrop()
.fit()
.placeholder(defaultImageLink)
.error(R.drawable.user_placeholder_error)
.transform(new RoundedTransformation(500, 1))
.into(imageView)
We can also resize the image as required by the imageview which will save memory usage if the image too large.
Callback method can be used to hide the progress bar and show some text within the image View on image load fail.
Picasso.with(context)
.load(url)
.placeholder(R.drawable.placeholder_img)
.error(R.drawable.error_img)
.resize(450, 420)
.centerCrop()
.fit()
.into(imageView, new Callback() {
#Override
public void onSuccess() {
progressBar.setVisibility(View.GONE);
}
#Override
public void onError() {
progressBar.setVisibility(View.GONE);
image_failed_text.setVisibility(View.VISIBLE);
}
});
Related
I am new in android developing and i have an issue. I try to load some images in a RecyclerView. The incoming data have the type byte[].
My first solution is converting byte[] to Bitmap and it works fine but the bitmaps stucks in the memory and i was getting an OutOfMemory exception.
The second solution is using Glide.
Glide.with(mContext)
.load(field.getImage())
.into(holder.mImageView);
But with this solution i get same images in each item.
I think the problem is in the Glide's cache because incoming arrays are different. I try to do solve this with this code:
requestOptions.skipMemoryCache(true);
requestOptions.diskCacheStrategy(DiskCacheStrategy.NONE);
Glide.with(mContext)
.applyDefaultRequestOptions(requestOptions)
.load(field.getImage())
.into(holder.mImageView);
}
But it doesn't help. What is the right way to do this?
try this use setDefaultRequestOptions(requestOptions)
Glide.with(context)
.setDefaultRequestOptions(new RequestOptions().placeholder(R.drawable.booked_circle).error(R.drawable.booked_circle))
.load(url)
.into(imageView);
you can resize image like this
Glide.with(PhotoGalleryActivity.this)
.using(new FirebaseImageLoader())
.load(storageReference)
.asBitmap()
.into(new SimpleTarget<Bitmap>(520, 520) {
#Override
public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) {
holder.img.setImageBitmap(resource);
}
});
For resizing image and adding (placeholder and error image) use this code:
RequestOptions requestOptions = new RequestOptions();
requestOptions.placeholder(R.drawable.app_icon);
requestOptions.error(R.drawable.ic_image_error);
Glide.with(context)
.setDefaultRequestOptions(requestOptions)
.asBitmap()
.load(newsContentModel.getImgNewsUrl())
.into(new SimpleTarget<Bitmap>() {
#Override
public void onResourceReady(Bitmap bitmap, Transition<? super Bitmap> transition) {
// requestLayout()
// Call this when something has changed which has
// invalidated the layout of this view.
myViewHolder.imgImage.requestLayout();
myViewHolder.imgImage.getLayoutParams().height = newHeight;
myViewHolder.imgImage.getLayoutParams().width = newWidth;
// Set the scale type for ImageView image scaling
myViewHolder.imgNewsImage.setScaleType(ImageView.ScaleType.FIT_XY);
myViewHolder.imgImage.setImageBitmap(bitmap);
}
});
I'm doing something like this to get bitmap synchronously and set it as image by using imageView.setImageBitmap(bitmap);
return Glide
.with(mContext)
.load(url)
.asBitmap()
.into(width, height)
.get();
I need to do it synchronously because I'm doing it inside AsyncTask's doInBackground. I need to fetch image url from the backend before loading it with glide.
Later I'm loading the same url into view directly with glide.
The problem is that image is not cached in the disk.
Any solution for this?
Use diskCacheStrategy
return Glide
.with(mContext)
.load(url)
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(width, height)
.get();
add diskCacheStrategy to your Glide, Select StrategyType as Source
You can have idea why to use SOURCE from this link
DiskCacheStrategy.NONE caches nothing, as discussed
DiskCacheStrategy.SOURCE caches only the original full-resolution image.
DiskCacheStrategy.RESULT caches only the final image, after reducing the resolution (and possibly transformations) (default behavior)
DiskCacheStrategy.ALL caches all versions of the image
try:
to get Bitmap From URL:
return Glide
.with(mContext)
.load(url)
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(width, height)
.get();
For loading in ImageView :
Glide
.with(mContext)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(imageView) // your ImageViewID here
For loading Image into ImageView after getting Bitmap:
Glide.with(context)
.load(url)
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(new SimpleTarget<Bitmap>() {
#Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
iv_image.setImageBitmap(resource); // you can store resource to some variable too if you want to update more than 1 images or try it like iv_image2.setImageBitmap(resource)
iv_image.requestLayout();
}
});
I have faced this issue many times the best way to overcome it is by using interfaces to load data after it is fetched inside glide CustomTarget
Create a new file called OnglideLoaded.java file like this:
import android.graphics.drawable.Drawable;
public interface OnGlideLoaded {
void onGlideLoaded(Drawable drawable);
}
Now create setter method for it like this where glide is:
public void setOnGlideLoaded(OnGlideLoaded onGlideLoaded) {
this.onGlideLoaded = onGlideLoaded;
}
Not call it inside Glide Target:
Glide.with(context)
.asBitmap()
.load(uri)
.into(new CustomTarget<Bitmap>() {
#Override
public void onResourceReady(#NonNull Bitmap resource, #Nullable Transition<? super Bitmap> transition) {
icon = resource;
if (onGlideLoaded!=null){
//This will send the image to every registered interface
onGlideLoaded.onGlideLoaded(icon);
}
}
#Override
public void onLoadCleared(#Nullable Drawable placeholder) {
}
});
Now call the interface like this where you want the image:
reference.setOnGlideLoaded(new OnGlideLoaded() {
#Override
public void onGlideLoaded(Drawable drawable) {
imageView.setImageBitmap(drawable);
}
});
Here, reference will be the object where you created the setter method.
By using the Glide image loader library, you are able to be notified if the began loading has succeeded.
Glide
.with(this)
.load(uri)
.asBitmap()
.listener(mRequestListener)
.into(imageView);
It works well, because you can get the bitmap loaded by Glide on the onResourceReady callback method of the RequestListener class. Now use an error placeholder:
Glide
.with(this)
.load(uri)
.asBitmap()
.listener(mRequestListener)
.error(R.drawable.error_image)
.into(imageView);
What if I want to get the error image?
When the given image couldn't be found and my error image loads, only the onException callback method gets called and hence this, we can't get the error bitmap.
Are you looking for something like this:
Glide.with(context)
.load(uri)
.asBitmap()
.into(new SimpleTarget<Bitmap>(width, height) {
#Override
public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) {
// add image to the imageView here
}
#Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
// you are given the error drawable
}
});
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
I am using Picasso library to load images stored on my server to my android application.
I am using the normal code to do this.
Picasso.with(context)
.load(url)
.resize(50, 50)
.centerCrop()
.into(imageView)
but now i want to set this image as a backgroud to my listview with id = myList .
Any help would be appreciated.
Thank you. :D
You could try to override the new target() implementation to set your view.
Picasso.with(context).load(url).into(new Target() {
#Override public void onSuccess(Bitmap bitmap) {
// Set imageview bitmap here.
// Do other stuff.
}
#Override public void onError() {
}
});
Please take note that the above won't work inside a ListView unless you implement hashCode/equals in your Target.
Implement the Target class.
Pseudo code:
Picasso.with(context).load(...).into(
new Target() {
public void onLoaded(Bitmap bitmap, Picasso.LoadedFrom from){
mListView.setBackground(bitmap);
}
/* ... */
}
);
Note that this code will not compile, as I don't know the exact API's, but this will help you further.