This is a general question about the way in which Android manages Bitmaps. I am wondering if it is better from a memory perspective to provide correctly sized Bitmaps to ImageViews rather than incorrectly sized Bitmaps that Android has to scale. For a working example if we assume an ImageView 1000 x 1000 and I set a Bitmap that is 1024 x 1024 (FitCentre) Android will have to scale the image. Does it then have to hold on to both the original image and the scaled version, more or less doubling memory usage? If in the alternate scenario I present a 1000 x 1000 Bitmap to the 1000 x 1000 ImageView, is only one image held? Just a question so I know the most efficient way to handle Bitmaps, particularly large images.
The Android will scale your image, but this will happen after your image has loaded in memory, and it won't prevent the notorious OutofMemoryError exception from happening.
The solution would be to scale the image before loading it in memory, and then use it.
The Android documentation explains in details how to mitagate this issue, and in general how to display Bitmaps efficiently: http://developer.android.com/training/displaying-bitmaps/index.html
Related
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.
In terms of RAM utilized by a drawable when it is rendered on on the screen, does it make any difference if the drawable is a vector or a bitmap?
I understand that vectors take less media storage space, but I'm asking about the resident RAM needed in order to render it, since in theory, it is still being drawn onto a canvas with the same amount of pixels in the end.
Thanks!
From the document I read sometime ago (same question with you).
The different between these 2 options is the size of APK file after all when you release. SVG will help you save size of apk.
The initial loading of a vector graphic can cost more CPU cycles than the corresponding raster image. Afterward, memory use and performance are similar between the two. We recommend that you limit a vector image to a maximum of 200 x 200 dp; otherwise, it can take too long to draw.
Being drawn on view will have those 2 options having same RAM (memory) consumed.
My reference source: https://developer.android.com/studio/write/vector-asset-studio.html#about
use vector drawables for simple shapes. Using the same for complex structures will increase the size of the apk rapidly.
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.
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).
I am fighting against OutOfMemoryError in my app.
I created a background image, which is 800 pixel x 480 pixel. When this image is loaded into the view that uses it as background, I think the OS will use 800*480*4 bytes for it. It is a lot of memory.
If I create a 10 pixel x 10 pixel 9-patch image to replace the whole screen image. The OS will auto-scale the 9-patch image to 800x480 when it renders the view that uses the 9-patch. My question is that, in the 9-patch case, how much memory will OS use to draw the scaled 9-patch image? will it be 10*10*4 bytes or 800*480*4 bytes?
Thanks.
Firstly, if it is a background image, and could be scaled, please do so, as it is known to be the best practice (especially for backgrounds) and the slight loss of image clarity could be compensated by choosing the correct colours and/or background pattern.
Regarding memory, if you are using Drawable you are on the safe side. But the Bitmaps are apparently not allocated in a standard Java way but via native calls; the allocations are done outside of the virtual heap, but are counted against it. More on this problem here