Example of Android Method for Loading Large Graph Efficiently

  • 2021-11-02 02:19:46
  • OfStack

Loading large images into memory is a headache. Because of the big picture, we will see OOM (out of memory) in the Crash report. Android has limited memory, which we should know well.

There are many answers to related questions on stackoverflow. When you encounter oom, you can skip this article and paste and copy the answers. But for others, I want to tell you a little knowledge and principle of loading large graphs.

Load Bitmap into memory

so easy. All you need to do is decode your picture using BitmapFactory.


Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage);
imageView.setImageBitmap(bitmap);

Does it look like it's over? I want to tell you that there is a problem here. Let's look at the memory size of the decoded picture.

bitmap. getByteCount () returns the size of the picture. Its memory size is 12262248 bytes, which is equal to 12.3 MB. Yes, you may have some doubts. The size of the picture on disk is 3.5 MB, but getByteCount () yields a result larger than 3.5 MB. The reasons are as follows:

Images are compressed in JPG, PNG, or other formats and stored on your computer. 1 Once you load the image into memory, the image will not be compressed, but take up the memory required by all pixels.

Steps

You don't need to load pictures into memory to get their dimensions Calculate the scaling factor from the picture size Load the picture into memory through the calculated value

BitmapFactory.Options

This class is a metadata provider, which can be used to complete step 1.


BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage, options);

We pass the BitmapFactory. Options instance to the BitmapFactory. decodeSource () method. We set inJustDecodeBounds to true. What does inJustDecodeBounds mean? That is, we don't have to talk about loading pictures into memory. We just want information about the pictures. We can calculate the scaling factor from this information.

Run this code to get the following information:

options.outHeight : 1126
options.outWidth : 2000
options.bitmap : null

Reduce picture size (in memory)

Now it's time to calculate inSampleSize. Wait, what is inSampleSize? inSampleSize is a scaling factor that belongs to the class BitmapFactory. Option.

If we have a picture of 1000 1000, the inSampleSize is 2, and the decoded size is 500 500.


BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inSampleSize = 3; 
BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage, options);

Can we play like this? No way. Because we don't know the size of the picture, if it is a small picture, the picture will become smaller, and our users can only see 1 pixel instead of the picture. Some pictures will be scaled 5 times, while others will be scaled 2 times. We define the scaling factor as a constant. So we need to calculate according to the picture size.

The method of calculating inSampleSize is up to you. I mean, design your own algorithm according to your needs. In the official document of Android, inSampleSize is calculated based on the power of 2.


options.inSampleSize = calculateInSampleSize(options, 500,500);
options.inJustDecodeBounds = false;
Bitmap smallBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage, options);

We change inJustDecodeBounds to false to get bitmap.

Now, bitmap. getByteCount () returns a size of 3.1 MB. This is the memory size.

The memory size of the picture changed from 12.3 MB to 3.1 MB, which reduced the memory size by 75%.

Reduce picture size (on disk)

We can also reduce the size of the picture on disk. We can compress pictures by compress method of Bitmap.

Let's look at the size of the image quality without changing the edge. 100 means the same quality


ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
byte[] bitmapdata = bos.toByteArray();

The size of the original image is 1.6 MB. What will happen to the file size after changing the image quality?


bitmap.compress(Bitmap.CompressFormat.JPEG, 50, bos);

Image quality changed to 50, size changed to 24.4 KB

If you want to change the quality of bitmap, the compressed format must be. JPEG, and the image quality of PNG format will not change.

The file size has changed from 1.6 MB to 24.4 KB.

Translated from: Loading Large Bitmaps Efficiently in Android


Related articles: