-
Notifications
You must be signed in to change notification settings - Fork 6.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Wrong images being loaded in Recycler View's grid on Some devices #601
Comments
To be honest, while reading your description I was really surprised by the issue, based on what you have in code. I don't see anything weird in there. Is it consistently happening to them? Is it always the same image? Is it possible that they have the wrong files in One thing you might try is to generalize your aspect view, since we have no idea about the cause, it may or may not help:
|
I am not using any networking library as my app doesn't require to be online for its functionalities. All the images my app uses are local images from the device itself. In my app, I have created an Image Picker using which user pick images to use in the app. The weird thing is that the Image Picker is also using RecylerView GridLayoutManager, but they haven't reported anything about the picker. They say they are able to reproduce the issue almost every time. The issue isn't related to any particular image as I have seen the videos they have sent me. There is nothing wrong with images in In all the screens where there are image grids( except for image picker), there are two different recycler views used but I don't think it has anything to do with that. |
Don't rule out anything yet. Just to be sure double check that you're not sharing any Adapter/Layout/... between the two lists. You can try to ask them for a backup of your app: http://www.howtogeek.com/125375/how-to-create-a-full-android-phone-or-tablet-backup-without-rooting-or-unlocking-your-device/ (you can replace all that SDK install with minimal ADB) and then you can restore it to your own device to see if you can reproduce it. Sadly, again, this may not work due to "There is nothing wrong with images", but there may be other switches in settings or database (if you have one), you know these parts best. Another idea: Do you have any w600-like resource folders? Maybe it only happens if a particular constraint is met, like big screen, or as simple as landscape, and you have different parameters to the RecyclerView layouts or the item layout in those different folders. You can try to set up a Genymotion emu for the Galaxy Tab to try to reproduce. |
One more: do you have any |
All the recycler views use their individual adapters and layout and nothing is shared between them.
I am not using The flow used in my app is that:
4.The |
I really hope that my below theory is correct and this solves your issue. I think you can likely reproduce your issue by loading a lot of very small images on a fast phone with your current code. From your flow description it sounds like a sync issue: imagine that an addition notifies the adapter and RecyclerView starts updating. It has to rebind all visible items so it goes sequentially. It reads item Assuming your SaveImageTask looks like this:
change it to:
This way access to the adapter and its model is ordered by the main thread's queue. I think another, cleaner and probably faster way would be, based on the above idea is to write an AsyncTask<String, File, Void> (media url String, saved File, nothing) and use onProgressUpdate to batch UI refresh for all selected files. You can use Glide synchronously with: Feel free to ask for clarification if you're having trouble implementing this. Happy to sketch up what I described above in compilable code. |
Thanks Róbert for your reply. So SimpleTarget could be the problem here?
All the videos that I have seen about this issue looked like are produced using small images.
My SaveImageTask works just like this. I always refresh adapters on the main thread. I will surely try |
Which method do you use to notify the adapter?
That debunks my theory :( it sounded convincing though. I'm out of ideas. @sjudd, anything to add?
Another idea to consistently reproduce this is to put a
I remembered the IOTools.writeAllBytes(fileInImageDirectory, Glide
.with(this)
.load(sourceUri) // can be a random content Uri too held in Intent.getData()
.asBitmap()
.toBytes(CompressFormat.JPEG, 80) // forwarded to Bitmap.compress
.diskCacheStrategy(DiskCacheStrategy.NONE) // no point in caching because it's saved to a File anyway
.skipMemoryCache(true) // make sure to re-read if original image changed
.atMost() // together with into() no image dimension will be bigger than the requested max
.into(2048, 2048) // both the same, but aspect will be kept
.get() // makes the Glide call sync, but has to be called on a background thread
);
publishProgress(fileInImageDirectory); I use something like this myself to load user picked content from Gallery (or any other external app). |
No great ideas unfortunately. Maybe try with a standard ImageView instead of AspectRatioImageView? It's also possible there's a Bitmap re-use issue on that particular device. You could try disabling BitmapReuse (call setBitmapPool(new BitmapPoolAdapter() in your GlideModule) for that device and see if that fixes the problem. |
I had a similar issue and I don't think that this is an issue with the Glide library. This seems to be related to RecyclerView#onBindViewholder reusing the views. The common solution to this problem is to set the ImageView's drawable to null on each call to onBindViewholder. |
That shouldn't be necessary. When using Glide inside an adapter, the The problem here is that the wrong image shows up after the newly bound image has been loaded, so it can't be residue. That being said I noticed that @gauravlnx you inlined the Glide line in your opening comment for brevity. Is there something you missed, like a conditional Glide load? If you have |
I am not using any conditional Glide load. The code in the onBindViewHolder mentioned in the first comment is all that I am using. My client had tried a different device and reported that the issue is not there on the new device. The situation on the Samsung tablet is still the same. |
Try disabling Bitmap re-use as I suggested above and see if it works. It's plausible that there are framework or manufacturer bugs on older devices, which would explain why you only see the issue on a Samsung tablet. |
Let us know if you figure this out or if we can provide any more suggestions. |
in RecyclerView.Adapter,please set setHasStableIds(true), and getItemId(position) |
Hello there, thought I'd revive this issue because I'm seeing a similar thing. In my case, it's loading small icon images (~200x100) over the network, and I'm only seeing the issue on Android 5.0 devices (I can reproduce locally on my Nexus 5). When I switch to using my own simple async image loading, I don't see the issue. I'm using glide elsewhere in my application for larger images in grid views, and not noticing anything wrong in those use cases. In the error case, I have a list of 32 objects, each of which has an image url and a title. The Image is a logo which says the title, so it's easy to see when the issue happens, because the image says one thing and the title says another. Everything usually appears in the right place during the first scroll down, but as you scroll more, things get more and more out of sync. @zhanghuaxin - I've tried your suggestion, it hasn't worked. My code is simple:
Please let me know if you guys are aware of the issue and if there's anything else I can do to help resolve. |
@levischmidt, thanks, let's go another round, maybe we find something new. Here are a few questions for you:
Re @zhanghuaxin's suggestion: it shouldn't matter matter if the ViewHolder is re-used or not, Glide's memorycache makes it efficient in every case. |
Hey @TWiStErRob - thanks for your reply and for re-opening. I was about to start making a small repro app, and stumbled upon a HUGE new piece of info about this issue - I was previously calling Anyway, when I take out this builder.setMemoryCache line, I can't repro the issue! Wanted to share that tidbit in case it helps you better understand what might be causing the issue. I'll also see if I can build a small repro app. I'll keep you updated. Thanks! |
Hmm, can you please try if you can repro with |
Yep, Still reproducible with I can repro on my Nexus 5, Android 5.0, by scrolling all the way down, then when scrolling back up, check to see if some of the images don't match the service name - usually I see the "WE Tv" image used for the "Disney" label, and the "A&E" image used for the BET logo (see attached screenshots). |
Can you please share the sources too? I don't think we can properly debug without them... |
I tried scrolling up-down on my Galaxy S4 4.4.2 and Genymotion Nexus 5 5.0, and it did not repro yet. How often does it show? How fast are you scrolling? Do I need to clear to cache to repro? |
Sure, source is attached. I'm able to repro 100% of the time with my Nexus 5, 5.0, and an LG GPad 5.0. No Need to scroll fast or clear the cache. Just slowly scroll down then back up. Haven't been able to repro with any other Android version other than 5.0. Try with the attached source. |
one more piece of info - I'm NOT able to reproduce the issue on a Nexus 5, 5.0 Emulator. Only on actual devices so far. |
I tried physical Nexus 7 (2012) 5.1.1 and Xperia Z 5.1.1 and it's no repro yet. I have exhausted my households devices ... @sjudd? |
I can't repro on 5.1. Only on 5.0 |
I've repro'd on Nexus 5, 5.0.0, and LG GPad, 5.0.2. Haven't been able to repro on any 5.1.x devices |
Ok, thanks for confirming, the bigger device sample the merrier :) |
Hi all, maybe you solved that. But today I had the same problem using glide inside of RecyclerView. |
@ferPrieto can you please share your device and version? And please check if you can reproduce it with the APK provided above by @levischmidt. |
My device is Huawei Nexus 6P with the Android Vesion 6.0.1. I have tried directly your code and it works perfectly and I have added ".placeholder(R.drawable.someimage)" and works too. I also have tried in BQ Aquaris M5 with Android 5.0.2 and both cases work good. |
So you were not able to reproduce the issue with the APK above? (If you say it works, it means you likely had a different issue) |
I had exactly the same problem, with the same kind of code. I wasn't using the APK above, but my code. |
We're looking for a consistent repro case that manifests the issue on most devices. Without a repro we can't fix the bug because there's no easy way to validate any fix. The APK (or any publicly available source that demonstrates the issue) should be an easy way to have a consistent repro. I tried multiple devices and failed to reproduce. I asked you to try your device so we can extend the list of device/version pair to maybe find a pattern. Using any kind of workaround (like adding a placeholder) will help you in the short term, but it won't help fixing the real problem. In general over time these little bugs may add up and any system experiencing this becomes unmaintainable. Glide is quite stable, but if we don't put effort in to finding and fixing these problems it will cost a lot of aggregate man-hours around the world... Your recognition of similarities in code doesn't mean you have the same problem, this is the biggest issue: the code above is extremely common and should work in 99% of the cases, that 1% is what we need to deal with without sweeping it under the rug. I hope this helps in understanding why I'm asking what I'm asking. Anyone who can reproduce this issue should tell that fact along with device/version/code if any. I'm hoping that Sam may be able to repro this when he gets around to it. |
Hey @TWiStErRob - any movement on this? I'm confident that it is reproducible on any 5.0 device using the apk or source zip I provided above (must be 5.0.x, not 5.1.x or 5.2.x). I've reproduced on various devices on 5.0, as well as by flashing a nexus 5 with a 5.0 build. let me know if I can be of any assistance it getting this solved! thanks! |
I think this issue was with a version of Android lollypop most probably 5.0. I don't remember the exact Android version but from the video my client sent it looked like lollypop. All the devices that I had were on kitkat or lower. |
I can reproduce the same issue on Note 4 (5.1.1) and Samsung Galaxy S6 (5.1.1). |
@TWiStErRob Using the sample APK provided above, I can reproduce the issue on my Galaxy S4 running 5.0.1. I happened to observe the issue in my app and came here via search. |
Huh, I gave in another try on my new Galaxy S5 (5.0.0) and I was able to repro, though it took a while to find a consistent one: Cinemax at the bottom usually has the wrong icon. I'll take a look tomorrow, fingers crossed I can repro it while a debugger is attached... |
I noticed in the logs these lines correlate with the wrong placements:
then I went ahead and put this into the builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888); which fixed the issue, but still don't know about the root cause. I also noticed that there's a border appearing sometimes around the wrongly placed images: Enabling more logging revealed that some images are loaded as 565 and some as 8888, even when decode format is Setting builder.setBitmapPool(new BitmapPoolAdapter()); also fixes the issue, but it disables bitmap re-use, which is at the core of Glide's performance. I went down a level (
and then I put a breakpoint to see what's the actual Bitmap in memory. The bad news is that Glide is loading the correct image into the Bitmap according to the debugger's "View Bitmap". To double check I dumped the bitmaps for Cinemax position to the sdcard via imageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); Notice that it's not even about recycling, as the above example suggests. It's not Disney's image showing up (where the viewholder came from), but the image just above the current item, most likely the most recent GPU-uploaded/rendered texture. I also tried a lot of combinations of these: imageView.setWillNotCacheDrawing(true);
imageView.setDrawingCacheEnabled(true);
imageView.postInvalidate(); but it didn't help. SummaryAccording to the above investigation I think the problem is in the framework, it mixes up OpenGL textures, and I found no way to detect if it'll happen or not from code yet. From the above workarounds the best solution is setting @sjudd or anyone else: what can we do about this? |
This issue has been automatically marked as stale because it has not had activity in the last seven days. It will be closed if no further activity occurs within the next seven days. Thank you for your contributions. |
This problem comes when the bindViewHolder logic is coded wrongly. I had a similar problem and this is how i solved it import com.bumptech.glide.Glide; import net.webnetworksolutions.mama.R; import java.util.List; /**
public class CountiesAdapter extends RecyclerView.Adapter<CountiesAdapter.MyViewHolder> {
} |
I have faced this problem on Xiaomi and Honor (Android Pie) with
|
In my app, I have a Recycler view with GridLayoutManager. The code I am using to load images bindImage method of recycler view adapter:
The Cell layout I am using is:
Here AspectRatioImageView(subclass of ImageView) automatically resizes the height of image view according to the provided aspect ratio.
The above code is working fine on my devices (Xiaomi MiPad, ViewSonic Tablet, Android emaulators and Samsung Galaxy S3) but is not working correctly on my client's device (Samsung 10.1 inch tablet).
In his end, images are being duplicated in the recycler grid. Also the the duplicates mostly occurs in adjacent recycler grid positions. I can't share any code as I even unable to reproduce the issue on my devices.
Do you guys have any idea what could the cause of this? Can you please suggest me any thing that I can try?
Thanks
The text was updated successfully, but these errors were encountered: