OutOfMemoryException while loading large size images using glide - android

So, I have been using this amazing library Glide for showing native images in my gallery app. I am using ViewPager with FragmentStatePagerAdapter to show full size images. The pager's off screen limit is 1 (default to save memory). I am using this code to load images into ViewPager in my fragment:
Glide.with(getActivity())
.loadFromMediaStore(uri)
.asBitmap()
.signature(new MediaStoreSignature(mimeType, dateModified,
.into(mImageView);
Now, I am facing some issues here like:
Images take quite some amount of time to load (if not cached). So, while user is scrolling through the viewpager blank screen is shown while image is loading which is what I want to avoid. Is there any way I can do this? Maybe by precaching images?
Sometimes, while scrolling through large size images (mainly Camera photos) OOM Exception is thrown and user is left with blank screen as no image is loaded. This also happens when I am shifting from potrait to landscape mode. So, I tried to use methods like atMost() -- which degrade the quality of image further as images are already loaded in RGB_565 and approximate() which is also causing OOM. How can I achieve maximum image quality without getting OOM exceptions?
For the second issue, I was thinking to load lesser quality images for the off screen items and then enhance quality when they come on-screen. Is it possible?
I have also tried to use ARGB_8888 but the result was same: OOM exception.

TL;DR
Make sure the ImageView has match_parent or fixed dp as dimensions
wrap_content makes Glide load full resolution Bitmaps.
.placeholder() shows an image instead of empty space while loading large bitmap
.thumbnail(float) loads a downsampled version fast while the bigger image is loading in the background
Also look around the Glide issues, maybe you find something helpful.
Details
I would be curious what the xml is for the ImageView, because my guess is it's wrap_content which results in loading images at full resolution into Bitmaps (using a lot of memory). If that's the case I would suggest using match_parent or fixed dp to lower the resolution. Note: you won't use detail, because currently the image is downsampled at render time anyway, just pulling that forward to decoding phase.
You also have to make sure that your app doesn't have constraints for memory usage. Can you load 3 (off screen limit = 1 means 1+current+1 pages) camera photos into Bitmaps without Glide? Again, assuming this is full resolution, it should be possible to store 3 screen size amount of bytes in memory with or without Glide, but you have to guide Glide to not load at full resolution.
You can load smaller sized image via .thumbnail(), it accepts a full Glide.with... not including .into() OR there's a shorthand parameter which is just a percentage (in 0.0 ... 1.0), try the latter first. It should decode the image much faster, especially with a really small number like 0.1 and then when higher quality one finishes it's replaced.
So the simpler option is to add .thumbnail() to your current load. A more convoluted one involves to start loading a lower resolution image with .sizeMultiplier() at the same time the Fragment's view is created and then start loading the high resolution one when the ViewPager has changed page. This helps with peeking the pages.
Alternatively you can just use a .placeholder() while the image is loading so it's not empty space, but "something" there.
Regarding using ARGB_8888 (32 bit per pixel): if you increase the memory consumed by Bitmaps (compared to RGB_565 (16 bit per pixel) don't expect to get run out of memory later. Once you get it working with 565 you can try increasing, but until then it's futile trying.
Also look around the Glide issues, maybe you find something helpful.

Related

Picasso unable to rapidly load images

I am facing an issue where Picasso is unable to rapidly load images.
There are 3 ImageViews which display left, middle and the right images.
On fast forward/backward, for a given time point, the left, middle and the right are chosen and displayed in the three box.
Here is the initialization. OkHttp cache is 100MB along with 99MB of LruCache
new Picasso.Builder(getApplicationContext())
.downloader(new OkHttp3Downloader(picassoOkHttpClient))
.memoryCache(new LruCache(99999999))
.build();
The number of images over which the window moves is 3000+. So I preload the images as
picasso.load(imageUrl).fetch();
Average image size is 10KB - 320x180 so it amounts to 35MB which is less than 99MB LruCache.
When the rapidly cycling through works, many of the images are GREEN (from MEMORY) and BLUE (from DISK) but then after few rapid cycles, the 3 images freeze or become very slow. At this time most of the images are BLUE. App is still responding. No OutOfMemory or any other exception.
android:largeHeap option is also enabled.
The hit ratio in the Picasso stats is very low. 150/3000.
The images are loaded as
picasso.load(leftUrl)
.noFade()
.noPlaceholder()
.into(leftImageView);
picasso.load(middleUrl)
.noFade()
.noPlaceholder()
.into(middleImageView);
picasso.load(rightUrl)
.noFade()
.noPlaceholder()
.into(rightImageView);
Issue 1 -> Picasso takes several minutes to download 3000+ images. Images load fast enough on other platforms and there is plenty of bandwidth (high enough to stream 4K)
Issue 2 -> Even after letting Picasso take its own time and finish loading all the images, it still freezes. Green ones are fast, Blue slower and then Blue ones freeze.
PS: I understand that "inflated" images will be much larger in size and will easily cross the 99MB bounds. That is why only some are green while most of them are blue.
The only reason I can understand fro your problem is that you are using images of very high resolution with huge size.
My suggestion for you is to resize the images while you are loading those images.
Something like that:
Picasso.with(getApplicationContext()).load(filePath).resize(400,400).centerCrop().into(imageView);
Hope this will help!
Try using another image loading library? Maybe the flaw is simply with Picasso. Personally i've never been fond of Picasso as it always had some issues. I've started using Glide, and can't find a single bad thing about it. It supports all kinds of caches and transformations, and it does it extremely well.
Examples:
- Glide
- UniversalImageLoader
- Fresco

Load Very Large Bitmap

I'm taking whole screenshot of a WebView and display the bitmap on an ImageView. The bitmap can be 7 screen height. (E.g. 1440x14000 px)
I'm frequently face with
OutOfMemoryError.
I've seen this
This says that load a scaled down version into memory but I don't want to lose image quality. There are the same approaches on the web.
Is there any way to handle OutOfMemoryError without loading scaled down version?
The bitmap can be 7 screen height. (E.g. 1440x14000 px)
Note that this means that the user cannot see the whole image at once at full resolution.
I'm frequently face with OutOfMemoryError
On most devices, you will have a very difficult time loading an image that large, as you cannot get a single contiguous memory block that big.
This says that load a scaled down version into memory but I don't want to lose image quality
To some extent, you do not have much of a choice. If you want the user to see the full extent of the picture at once, the image has to be scaled to fit the screen.
Is there any way to handle OutOfMemoryError without loading scaled down version?
There are ImageView replacements that offer pan and zoom. Some of those, such as this one, handle loading in pieces of the image at a time, with whatever scaling is necessary for the current zoom level, to make it more likely that you will be able to show the user the entire image.
It is not a solution, of course, but I'm also not familiar with your exact needs, so maybe this may help you a little - you can try to play with bitmap options during decoding. Try to use Bitmap.Config.inPreferredConfig as RGB_565 - this will reduce size of your bitmap twice comparing to default ARGB_8888. But, of course, if you use complex images in your web page this may reduce their quality.

How prevent Outofmemory Error loading big image?

I have a Scrollview that contains 4 big size images 750x1023, 750x2265, 750x1898, and 750x1112
I load image with Picasso
Picasso.with(getContext()).load(resIds[i]).fit().centerCrop().into(mainImageview.get(i));
But it brings to OutOfMemory error.
It makes to problem:
not all images load
app closing
Its important not to make image smaller - it can make UI uncorrect.
What the way to solve this problem? id need, to post code of program - just say what piece.
Thanks!
After all manipulation, problem is still unsolved.. If i scale images with BitmapFactory, it gives "Bitmap too large to bu uploaded into a texture", what ever size i write. If a scale with picasso, it crops my image What ever i do, app memmory enought for two, three switching pages... I'm exhausted because of this problem ...Help
The issue I believe is with gl max size which is something like 2048x2048 and the error will be cannot apply texture or something to that effect Picasso has a lot of ways to scale images but if you must use the full size image then its possible to cut the image into 4 or more pieces and assemble it like Google maps check this "Bitmap too large to be uploaded into a texture"

40+ ImageButtons on one screen?

For last 10+ hours I try to get a large (40+) amount of images (in ImageButton format) on a single Android screen without out of memory errors. The activity I work on is an image picker for a coloring book app. Images are of various sizes in the range of (500 to 1200)x(500 to 1200), PNGs (if that matters).
I have tried:
Horizontal Scroll View with images added from the code. The result is slow (I do it on UI thread) and consumes large memory space.
Horizontal Scroll View with images added from the code via AsyncThread. The result is fast but still consumes large memory space. I like the user experience of this one the most!
Grid View and List View - both are very choppy (testing on first Nexus 7). Memory usage is better.
What I am considering
View Pager - first results look better than Grid View from performance perspective (I have not completed it to the moment to assess the memory usage but it should be better from what I understand). Yet, I dislike the user experience and prefer a scrollable list of all images.
Conversion of my resources to JPG (will that get rid of Transparency byte?)
Downsizing the images to max 500x500px
None of the solutions seems as good as the Android Photo Gallery app available on all devices. This experience is what I would love to mirror. No idea how this is done though :(
Two questions.
What is the best way to get such thing (40+ Images scrollable on single screen) done? Is it really ViewPager? ScrollView with AsyncTask and well thought images resolution? Something I have not tried yet?
What is the memory limit I should try to keep below? Looking at Android heap size on different phones/devices and OS versions it seems to be 256 MB, is that fair assumption?
Thanks. Have a great weekend!
PS. On iOS all works like charm when I add all the buttons into a scroll view :(
Some basic calculations reveals your problem:
40+ images at 1200x1200 = approx 57MB, the comments are correct you need to subsample (i.e. thumbnail) the images or use a library such as the Universal Image Loader. Converting to JPG doesn't matter. That is a compressed storage format, the memory required to display the pixels remains the same.
There is a Android Developers article on Loading Large Bitmaps Efficiently with sample code. The following steps are covered in more detail in the article Android Bitmap Loading for Efficient Memory Usage.
The basic steps in loading a large bitmap are:
Determine the required size (from a known size or determining the
size of the target View).
Use the BitmapFactory class to get the bitmap’s size (set inJustDecodeBounds in BitmapFactory.Options to true).
Calculate the subsampling value and pass it to the BitmapFactory.Options setting inSampleSize.
Use the BitmapFactory to load a reduced size bitmap.

how device gallery show large images?

Whenever I try to show large size(1 MB) bitmap in imageview, system throw OutOfMemory exception.
If I place 7-8 MB image, gallery can easily show that image.
Just want to know How device default gallery is able to show large image in easy way?
Which mechanism is used by device gallery?
Generally speaking, they subsample the image. A 1MB PNG or JPEG file will be much higher resolution than the screen, and so it is wasteful to load the whole image in. Subsampling allows you to load the image in much closer to the actual size of the ImageView you will use, allowing it to fit in memory better. A simple approach to subsampling involves using inSampleSize on BitmapFactory.Options; Dave Morrissey's SubsamplingScaleImageView offers pinch-to-zoom and such while peforming subsampling (note: I have not tried this component, as I just ran across it a minute ago).

Categories

Resources