I have a gallery working in my app at the moment with about 8 pictures on it. Before i had a bug that use to make it crash because of overload Heap (something like that, not sure).
This was caused by my pictures being too big in file size, so i reduced them it worked. So my main question is How many picture can i actually put in to my app.
I was hoping to have about 5 screens (activities) with some scrolling pictures
I don't want to start changing my app if its just going to crash again
Also does anyone know how to add transitions when scrolling through pictures, for it too look fancy
Everything depends on the way you manage you pictures. To save the memory (and increase the number of images loaded) you should load a resized picture.
You can subsample picture while loading:
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 2;
BitmapFactory.decodeResource(res, id, opts);
This will load a picture scaled 1/2 of it's original size (keep in mind that subsampling works only for power of 2 values). You can load the picture smaller than the area it will be displayed in and let ImageView to upscale it.
If your loaded image is still too large, you can scale it more with Bitmap.createScaledBitmap().
You should be aware that pre-Honeycomb Android doesn't recycle bitmaps like post-Honeycomb Android does. You should call Bitmap.recycle() as soon as the bitmap is not used anymore to clear the memory.
For image scrolling you can use ViewPager.
Further reading: http://developer.android.com/training/displaying-bitmaps/index.html
There is no strict limit on the number of pictures you can include in your app. See the stock Gallery app as an example, I consider myself a relatively light picture taker, but I still have hundreds of images in my Gallery. If you follow the Bitmap best practices you shouldn't run into any memory issues, and you should be able to include as many images as you want.
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.
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.
I'm having serious issues with memory, and I'm looking forward to recycle bitmaps.
However, what my app is doing atm, is building a Gallery (yeah, the deprecated) with several bitmaps, and then, several Galleries.
So at the end of the day, the app looks like (LinearLayout style):
*Some webviews
*A Gallery with 7 images.
*Some webviews
*A Gallery with 10 images
and so on.
So what I'm thinking is... Once I've displayed those images, and them are on the screen, can those bitmaps be recycled?
Is there any way to recycle a whole Gallery component?
Thank you so much.
Edit:
I've tried soo many things. I'm still getting the error java.lang.IllegalArgumentException: bitmap size exceeds 32bits
This is my actual code:
BitmapFactory.Options bfOptions=new BitmapFactory.Options();
bfOptions.inDither=false; //Disable Dithering mode
bfOptions.inPurgeable=true; //Tell to gc that whether it needs free memory, the Bitmap can be cleared
bfOptions.inInputShareable=true; //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
bfOptions.inTempStorage=new byte[32 * 1024];
bfOptions.inInputShareable=true;
bfOptions.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeFile(mUrls.get(position).getPath(), bfOptions);
inflatedImageView.setImageBitmap(Bitmap.createScaledBitmap(bitmap, 120, 120, false));
As you can see, I've set many options to the Bitmap, aswell as resizing it, and lowering it's quality. Still happenning the same issue.
First you should never manually call system.gc, and generally there is no need to manually recycle bitmaps either. Let the operating system do what its best at, deciding when to take the huge hits to run garbage collection.
One of the reasons that gallery was deprecated is I am fairly sure it just loads all items as soon as it renders. And does not load them and recycle them on demand like a list view. Which means it is a huge waste of RAM and no amount of recycling will help you. In addition Gallery is very glitchy on 4.0+ phones, which is the majority of the Android user base at this point. I would strongly recommend you move away from using gallery.
There are two alternatives.
1) View Pager which is now built into the Support V4 library
2) HorizontalListView --> https://github.com/MeetMe/Android-HorizontalListView
Also be absolutely sure you are downsampling all images prior to loading them in the image views. To learn how read http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
Ok. I solved the issue I was having; I had a linearLayout with gallery components and webviews. If I didn't render the webviews the app didn't crash.
So after some tweaks now it's working correctly without crashes:
wv_detail.getSettings().setRenderPriority(WebSettings.RenderPriority.HIGH);
wv_detail.setLayerType(View.LAYER_TYPE_NONE, null);
I am writing a Android app which need to display some high quality picture(took from professional DSLR). The problem is it can't be display from gallery.
I choose a photo in Gallery first. The target picture is 2464*1632 JPEG, roughly 4.5M;
Then I just need to compress it to 800*600 and display it in imageview:
image.setImageBitmap(this.bmp);
Thing is that I have tested other image I downloaded form internet(really low quality), and it works without any problem. Can anybody tell me why it can't be displayed? I will be really appericiated
Large images are tricky to handle due to limited memory. You have several choices:
Use a WebView (this allows you to have pinch and zoom functionality to make use of those extra pixels
Decode the image down to the size of the display and then put it in an ImageView using BitmapOpts http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html and changing inSampleSize. It seems you may be having difficulty with that, so consider using createScaledBitmap which just needs the dest width and height.
I know there is a lot of discussion about android bitmap images out of memory but I was wondering if someone could explain it to me..
Currently in my app I have an activity which lists image thumbnail (low quality) and when I click an image it opens a new activity to view the image full screen. In my 2nd activity class I have:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
bm = BitmapFactory.decodeFile(myImagePath, options);
I then put this into an ImageView to display it. This works and displays my image to its full quality. However if i click back and then click to see that image again (and repeat this 6 times) .. on the 6th time opening the image (activity2) I get an out of memory error saying Heap size=6919KB, Allocated=3125KB, Bitmap Size = 25848KB!
How is bitmap size that big? I assumed it may be creating new instances all the time so I then decided to put a method in my 2nd activity for when the back key is pressed..and in this method I set my bitmap=null and also did System.gc() to clear the garbage collector BUT this did not fix the problem. I still get an out of memory error on the 6th time of clicking on the thumbnail to view the image in full resolution
Can anyone explain why? Thanks
There is some great information from android that explains it all in detail, and how to overcome this problem here.
Each pixel is 4 Bytes. 6M Pixel = 24MBs
One photo can use up all the Memory.
Bitmaps take up a lot of memory, especially for rich images like photographs. For example, the camera on the Galaxy Nexus takes photos up to 2592x1936 pixels (5 megapixels). If the bitmap configuration used is ARGB_8888 (the default from the Android 2.3 onward) then loading this image into memory takes about 19MB of memory (2592*1936*4 bytes), immediately exhausting the per-app limit on some devices.
Again I point you to this great link I found from another SO Question that has tutorials of how to properly over come the problem.
inSample size should be set so that the image is scaled to the size of the display area (1 = full size) unless there is some reason you think you need all the bits of the image, so 2 would = 1/2 scale 4 1/4 scale etc.
Also try bm.recycle() when you are finished with the bitmap before using =null
Update
Look at the second answer what does recycle do unless you have already tried that and it didn't work. I have done similar things with loading images and never run out of memory, that's not proof that it will work for you, but it's a best practice as far as I can tell.