Android Bitmap Loading for Efficient Memory Usage

Load a Bitmap from Resources Correctly

When handling bitmaps it is not long before Android developers come across the error “java.lang.OutOfMemoryError: bitmap size exceeds VM budget“. This usually occurs when the bitmaps are large (several megabytes uncompressed),  or running the code on older devices, or trying to load lots of bitmaps. This occurs because Android was design for mobile devices with limited resources, including memory, and bitmaps can require large amounts of memory. Despite Android not dealing with multi-megabyte bitmap loading automatically it can still be done. Instead of loading the whole bitmap a reduced resolution version is loaded (via a technique called subsampling). Android bitmap loading is achieved via the BitmapFactory class. The Options settings passed to the class can reduce the size of the bitmap, saving on memory usage.

Bitmaps can be BIG but Android Screens are Small

A digital image from a camera can be between 5 and 18 megapixels (MP) in size, depending upon the camera or device. This is the uncompressed size. The actual file storing the image, usually a JPEG file, is smaller than the displayed image because of compression. High end cameras can produce 20 MP or higher images. A 5 MP image can have a resolution of 2560×1920, that is greater than high definition (HD) television at 1920×1080, and bigger than the resolution of the Goggle Nexus 10 tablet device at 2560×1600. What about a 18 MP image? A size of 5184×3456!  A Nexus 5 phone has a HD screen, so why load more than 2 MPs of data if the screen can only display a maximum of 2 MPs. By using subsampling the huge photo image being viewed on the Android device only consumes as much memory as required to display it, 2 MP for a HD resolution screen. This saves precious App memory and reduces the possibility of out of memory errors. Here’s an example of loading large bitmaps on different Android devices. A 1000×1000 placeholder image was loaded into an ImageView  and the App run on two devices. One with a HVGA, 320×480, screen and another with a QVGA, 240×320 screen.

Android Bitmap on Different Screens

On the HVGA screen the 1000×1000 image is shown at 320×320, on the QVGA screen it is shown at 240×240. So the one million pixel image only requires a hundred thousand or sixty thousand pixels for actual viewing on these devices. Loading only the required size for display makes sense. On the Android Developers website there is an article on Managing Your App’s Memory and in the section Avoid wasting memory with bitmaps it states: “When you load a bitmap, keep it in RAM only at the resolution you need for the current device’s screen, scaling it down if the original bitmap is a higher resolution.

Android Bitmap Loading Code from the Developer Site

There is a series of lessons on the Android Developers site called Displaying Bitmaps Efficiently that deal with correctly loading, caching and processing bitmaps. When processing multiple large bitmaps it needs to be done away from the User Interface (UI) thread using AsyncTask, with the use of caching when appropriate. There is a sample App for the lessons, DisplayingBitmaps.zip, for Android Studio, though the code can be used in Eclipse if that is your preferred development platform. The example App was previously called Bitmap Fun from BitmapFun.zip. The basic steps in loading a large bitmap are:

  1. Determine the required size (from a known size or determining the size of the target View).
  2. Use the BitmapFactory class to get the bitmap’s size (set inJustDecodeBounds in BitmapFactory.Options to true).
  3. Using 1. and 2. calculate the subsampling value (a multiple of 2) and pass it to the BitmapFactory.Options setting inSampleSize.
  4. Use the BitmapFactory to load a reduced size bitmap.

The following section takes the code from the Android Developers article Displaying Bitmaps Efficiently to provide an example App performing the steps listed above.

Sample Code to Load an Android Bitmap from a Large Resource Image

J. M. W. Turner The Fighting Temeraire A large bitmap is needed. You may be reading this because you have a very large bitmap causing out of memory errors. Here a large image of a Turner painting is used. The image size is 5684×4226, a 24 MP image! You can grab the image from Wikimedia Commons, it is available in several sizes.

An Android App project was created in Eclipse. The large Turner image was added to the project in a folder called drawable-nodpi under the res folder. A large placeholder image (large enough to match the screen width) was also added to the folder. It can be generated from Placeholder Graphic at openclipart.org. The layout is just an ImageView with a Button below it:

Here’s the code for the App:

And the App in action:

Large Android Bitmap Loading

Using a Open Source Library to Manage Large Bitmap Loading in Android

This code is good for a single bitmap, but the Android Developers article goes on to talk about caching and background loading. One way of achieving this is to use an existing implementation, such as provided in the Display Bitmaps sample or existing libraries that support large bitmap loading with caching, including android-query (AQuery),  Android Volley for loading images over networks and Android Universal Image Loader.

Related Article

How to Get a View Size in Android

How to Get View Size in Android

Determining the Size of an Android View or Screen at Run Time

For efficient bitmap handling or dynamic View creation in an App the area that a widget or layout is using needs to be known. If no fixed sizes are allocated at design time the size of a View may not be known until an App is executed. This is because of the wide range of display sizes that Android supports. The example code snippets in this articles shows how to read the screen size and the size of Views as the App runs. To run the example code you will need to create a new Android project (those new to Android programming can view the article Your First Android Hello World Java Program to see how), we called our App View Size.

In the layout designer for activity_main.xml (or whatever you called your layout) add another TextView, called textXY, next to the existing Hello world! widget. Change the Text on the first TextView to X,Y. Add this code to the oncreate method in MainActivity.java (or whatever class you are using), you will need an imports for TextView and DisplayMetrics. :

This is the code running on an AVD with a 320×480 screen:
Size of Android Screen

He is the layout used for this screen: Continue reading