Android: Glide onStart/onResume bug - android

I have a weird bug with Glide and i'm not sure what to do about it. Basically I have this function, which loads images from reddit.com/r/earthporn/
newsdata.data.children[position].data.url is a list of urls
public void displayImage(final int position) {
Drawable d = view.getContext().getResources().getDrawable(R.drawable.ic_collections_white_24dp);
System.out.println(newsData.data.children[position].data.url);
Glide.with(view.getContext())
.load(newsData.data.children[position].data.url)
.asBitmap()
.listener(new RequestListener<String, Bitmap>() {
#Override
public boolean onException(Exception e, String model, Target<Bitmap> target, boolean isFirstResource) {
displayImage(position + 1);
//todo: make sure we don't run into a index out of bounds.
return false;
}
#Override
public boolean onResourceReady(Bitmap resource, String model, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {
return false;
}
})
.centerCrop()
.error(d)
.into(new BitmapImageViewTarget(view.getImageView()) {
#Override
protected void setResource(Bitmap resource) {
super.setResource(resource);
view.setImageBitmap(resource);
wallPaperBitmap = resource;
System.out.println(resource);
}
});
}
Android can't load every single image that appears on the subreddit. When that happens, I load the next image down. On a run today, it will load this image http://imgur.com/HOSg2FC, call an exception, and then load this http://i.imgur.com/baluFH7.jpg
OnCreate, this code will run as expected. It runs, hits the exception, calls displayImages() again and sets the correct Image. (Please, let me know if there's a better way to do this)
OnResume/onStart is where the problem lies. The code will run, hit the exception, place the error drawable, call displayImages again but not change the imageview. setResource(bitmap resource) will also give me the correct bitmap but will not let me update the imageview at all.
Basically, it freezes the imageview to the error drawable, or to a blank white screen if there is no drawable and won't let me change it.
Calling onResume with the following code:
if(wallPaperBitmap != null) {
view.setImageViewPicture(wallPaperBitmap);
//view.showButtons();
System.out.println("bitmap != null");
}
else {
retrieveImage(SubReddit.Earth);
System.out.println("bitmap = null");
}
Will set the correct picture.
I thought maybe this might be a problem with the cache so I tried using diskcachestrategy.none but that didn't help either. As a last resort, I could probably refresh the screen once setResource is called with the updated bitmap or just use Picasso but I'd rather avoid that.
Any help is appreciated!
Edit: I'm also getting the error: D/skia﹕ --- SkImageDecoder::Factory returned null onStart

Glide may restart failed requests in onStart, which would trigger the failure, then set the error Drawable. To fix this, you should do two things:
Always call clear() on Views and Targets before calling setImageResource/setImageDrawable yourself (outside of onResourceReady). Calling clear() will prevent Glide from managing that View/Target, which in turn will stop Glide from restarting the loading in onStart.
If you ever keep a reference to a resource loaded by Glide (usually a Bitmap or a Drawable, you need to make sure to null out your reference when the Target's onLoadCleared or onLoadFailed methods are called. This isn't directly related to this issue, but it's an error in your code above and can lead to weird errors if Glide re-uses the Bitmap while you're referencing it.

Related

what if glide gives an error in andorid

I am stuck thinking that I am developing an which provide a way to advertise their products, but I am confused what if glide gives an error in certain position of recyclerview, what should I do and how to manage that? Should I remove recyclerview item at that position or do something else because it degrades my app quality? One more thing, why the popular apps ex: facebook, instagram does not get such errors, because I never found any error image in their recyclerview how they do it?
my backend is firebase;
If Glide cannot load image at specific place. You can use a placeholder or error to managed it.
See docs:
https://bumptech.github.io/glide/doc/placeholders.html
My Facebook app sometime cannot load image because my internet connection too slow, and it become blank.
Facebook and other application has button to retry, when error comes. you can do as below in bindViewHolder method for RecyclerView and getView method for ListView:
Glide.with(mContext)
.load(arrayList.get(position).getImageUrl())
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(new SimpleTarget<GlideDrawable>() {
#Override
public void onResourceReady(GlideDrawable resource, GlideAnimation<super GlideDrawable> glideAnimation) {
if (holder.mimageView.getVisibility() == View.GONE)
holder.mimageView.setVisibility(View.VISIBLE);
if (holder.btnRetry.getVisibility() == View.VISIBLE)
holder.btnRetry.setVisibility(View.GONE);
holder.mimageView.setImageDrawable(resource);
}
#Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
super.onLoadFailed(e, errorDrawable);
if (holder.mimageView.getVisibility() == View.VISIBLE)
holder.mimageView.setVisibility(View.GONE);
if (holder.btnRetry.getVisibility() == View.GONE)
holder.btnRetry.setVisibility(View.VISIBLE);
}
});
Now on btnRetry click you can again fetch image using glide as above.

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

Picasso Not Loading HTTP Facebook Link (NOT DUPLICATED)

Before you set the question/issue as duplicate, please read it all first.
I know it is a known issue and there's loads of question on Stackoverflow and issues on Github but believe me I tried them all.
ISSUE
Not loading this link:
https://scontent.xx.fbcdn.net/v/t1.0-1/p200x200/13872950_1066865640060722_8272182690153279858_n.jpg?oh=66a4ff80019c1fbf79bee45d32f03468&oe=59F65F50
MY CODE
Target target = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
userPicture.setImageDrawable(FunctionUtil.roundBitmap(bitmap));
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
Resources resources = getContext().getResources();
Bitmap bitmap = BitmapFactory.decodeResource(resources, R.drawable.ic_image_content_error);
userPicture.setImageDrawable(FunctionUtil.roundBitmap(bitmap));
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
Resources resources = getContext().getResources();
Bitmap bitmap = BitmapFactory.decodeResource(resources, R.drawable.ic_image_placeholder);
userPicture.setImageDrawable(FunctionUtil.roundBitmap(bitmap));
}
};
Picasso.with(getContext()).load(me.getPicture().getUrl()).into(target);
WHAT I HAVE TRIED
NO CACHE:
Picasso.with(getContext()).load(me.getPicture().getUrl()).memoryPolicy(MemoryPolicy.NO_CACHE).networkPolicy(NetworkPolicy.NO_CACHE).into(target);
NEW DOWNLOADER:
`new Picasso.Builder(getContext()).downloader(new OkHttpDownloader(getContext())).build().load(me.getPicture().getUrl()).into(target);`
BOTH:
`new Picasso.Builder(getContext()).downloader(new OkHttpDownloader(getContext())).build().load(me.getPicture().getUrl()).memoryPolicy(MemoryPolicy.NO_CACHE).networkPolicy(NetworkPolicy.NO_CACHE).into(target);`
What am I doing wrong?
Ok so the question was answered here:
https://github.com/square/picasso/issues/1658
My mistake was creating the Target as a local method property then when Picasso took a little bit more time to load the image maybe the Garbage Collector cleaned the Target reference which was make it impossible to Picasso to load it into the Target. That is why it SOMETIMES it worked.
SOLUTION
Create Target object as a global property inside the Activity to hold its reference for as long as you use the imageView you want to load the image into. That fixed the issue. :)
Thanks guys!

Glide wont load all images in ViewHolder

So I have a RecyclerView with a custom adapter and I use Glide to download images from a URL when applicable. Relevant code snippet here:
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
final Location location = mLocations.get(position);
holder.title.setText(location.getTitle());
if (location.hasImage()) {
String imageUrl = NetworkHelper.getImageUrl(getContext(),location.getImageName());
holder.image.setVisibility(View.VISIBLE);
// Use Glide for image loading
Glide.with(getContext())
.load(imageUrl)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.centerCrop()
.into(new GlideDrawableImageViewTarget(holder.image) {
#Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
super.onLoadFailed(e, errorDrawable);
e.printStackTrace();
}
#Override
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> animation) {
super.onResourceReady(resource, animation);
}
});
} else {
// Due to the nature of the RecyclerView, we need to ensure we clear
// out images to odd behavior.
Glide.clear(holder.image);
holder.image.setVisibility(View.GONE);
}
}
Problem is that the onResourceReady() method isnt always being called and hence not all images being loaded. Ive verified all the URL's being passed and they all seem fine. Is there a Glide specific issue here perhaps? If I take a URL that is not being loaded and hard code it into the imageUrl variable, its still not being downloaded, so there must be something specific to those images thats causing glide to fail. A timeout issue perhaps?
EDIT: I added the onLoadFailed method and it does hit, but the Exception is null, which is kinda weird. Basically same issue as described here: https://github.com/bumptech/glide/issues/741

Android Glide: How to download and cache bitmaps?

I am using Glide to download and cache images on Android. Everything works well except the fact that I don't want to load the bitmaps directly into the ImageView, I don't want to have the fade animation, neither image placeholders.
All I want is to create a global method which will help me to download the image all over the application.
public class MyApp extends Application {
public static void downloadImage(String url, final OnImageLoadedCallback callback) {
// And how to implement the listener ?
RequestListener<String, Bitmap> requestListener = new RequestListener<String, Bitmap() {
#Override
public boolean onException(Exception exc, String string, Target<Bitmap> target, boolean isFirstResource) {
callback.onDone(null);
return false;
}
#Override
public boolean onResourceReady(Bitmap bitmap, String string, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {
callback.onDone(bitmap);
return false;
}
};
Glide.with(context)
.load(url)
.asBitmap()
.dontAnimate()
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.listener(requestListener);
}
}
The problem is that I don't know how to implement the listener. RequestListener isn't called at all.
Loads in Glide don't start until you make a call to into. The RequestListener interface observes requests, but isn't typically meant for handling results. Instead of using RequestListener, consider having your callback implement the Target interface and pass it in using into.
Alternatively you could just extend SimpleTarget and pass it in to each request in the same way you're trying to use RequestListener:
Target target = Glide.with(context)
...
.into(new SimpleTarget<Bitmap>(width, height) {
#Override
public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) {
callback.onDone(resource);
}
#Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
callback.onDone(null);
}
});
// At some point later, if you want to cancel the load:
Glide.clear(target);
You will want to provide a width and a height so that Glide can downsample and transform images appropriately. You may also run in to issues with cancellation if you're displaying these Bitmaps in views, in which case I'd strongly recommend making the view available to your loading API and passing the view to into which will handle sizing and cancellation for you.
I use Glide 3.7.0 and download images this way:
it is important to note - it executes asyncroniously
Glide.with(this)
.load(url)
.downloadOnly(new SimpleTarget<File>() {
#Override
public void onResourceReady(File resource, GlideAnimation<? super File> glideAnimation) {
LOGGER.debug("Photo downloaded");
}
});
When I need to show cached image, I use the same url and DiskCacheStrategy.SOURCE:
Glide.with(this)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(imageView);
It is now even simpler on Glide 4.9.0.
Glide.with(this)
.downloadOnly()
.load(url)

Categories

Resources