Android - large image or multi-image loading solution (perfect solution to OOM problem) (transfer)

Reprinted from: http://www.2cto.com/kf/201407/321093.html

When developing an application, many times it involves the loading of a large number of pictures and the loading of high-precision pictures, both of which will cause the application The problem of OOM (OutOfMemory) occurs, and reasonable image loading and image memory management are the problems that must be solved. The following will provide a relatively complete technical solution to solve these two problems.


First of all, we must clarify why the OOM (OutOfMemory) problem occurs. The reason is that the OOM problem occurs when the system memory used exceeds the maximum available memory of the current APP during the running process of the APP. Next, let's estimate how many pictures loaded on a mid-to-high-end mobile phone will cause OOM: Assuming that the maximum available memory allocated to the APP by the system is 32M, loading a picture with a resolution of 512*512 will occupy 2M of memory space , In this way, when 16 pictures are loaded in the APP, OOM will appear. In fact, when more than 10 pictures are loaded, it is very easy to cause OOM, because the APP will still occupy memory during operation. (PS: Image occupied memory calculation: The default loading of Bitmap in Android uses ARGB_8888, and each pixel will occupy 4 bytes, because each pixel has two Chanels, so a 512*512 image, no matter what format, is loaded into memory. 512*512*4*2=2MB, therefore, the Android image occupies the memory size, which is only related to the resolution (pixels) of the image and the color mode used for loading)


To solve the problem of OOM, optimize from two aspects: 1. Reasonable Loading resources 2. Recycling resources


reasonably Loading resources

reasonably Loading resources reasonably, that is, if the ImageView displaying the image is only 128*96 pixels in size, it is obviously a wrong behavior to fully load a 1024*768 image into the memory at this time. . At this time, it is necessary to compress and load the image to be loaded, that is, to load the resources reasonably.

Next, let's explain the compression of pictures. Set the value of inSampleSize in BitmapFactory.Options to achieve proportional compression. For example, if we have a picture of 2048*1536 pixels, set the value of inSampleSize to 4, we can compress this picture to 512*384 pixels. Originally loading this image needs to take up 26M of memory, after compression it only needs to take up 1.5M. The following method can calculate the appropriate inSampleSize value according to the incoming width and height:

public static int calculateInSampleSize(BitmapFactory.Options options,
        int reqWidth, int reqHeight) {
    // The height and width of the source image
    final int height = options. outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;
    if (height > reqHeight || width > reqWidth) {
        // Calculate the ratio between actual width and target width and height
        final int heightRatio = Math.round((float ) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);
        // Select the smallest ratio of width and high school as the value of inSampleSize, so as to ensure that the width and height of the final image
        // must be greater than or equal to the width and height of the target.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }
    return inSampleSize;
}

After calculating the appropriate scaling ratio, then perform the actual compression of the image:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
        int reqWidth, int reqHeight) {
    / / Set inJustDecodeBounds to true for the first parsing to get the image size
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);
    // call the above definition method to calculate inSampleSize value
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    // Use the obtained inSampleSize value to parse the picture again
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}
After the above two steps, You can achieve reasonable loading of image resources.

Reasonable recycling of resources


Reasonable recycling of resources means reasonably recycling the image resources loaded in the memory to avoid the situation that the image resources that are no longer used are still stored in the memory. To achieve reasonable resource recycling, the core class is: LruCache. This class is very suitable for storing image memory. Its main algorithm principle is to store recently used objects in LinkedHashMap with strong references, and store the least recently used objects in LinkedHashMap. The object is removed from memory before the cached value reaches a preset value.

The specific usage method is given below:

private LruCache<string, bitmap=""> mMemoryCache;

@Override
protected void onCreate(Bundle savedInstanceState) {
    // Get the maximum value of available memory. Using memory beyond this value will cause an OutOfMemory exception.
    // LruCache passes in the cache value through the constructor, in KB.
    int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
    // Use 1/8 of the maximum available memory value as the cache size.
    int cacheSize = maxMemory / 8;
    mMemoryCache = new LruCache<string, bitmap="">(cacheSize) {
        @Override
        protected int sizeOf(String key, Bitmap bitmap) {
            // Override this method to measure the size of each image, Returns the number of pictures by default.
            return bitmap.getByteCount() / 1024;
        }
    };
}

public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
    if (getBitmapFromMemCache(key) == null) {
        mMemoryCache.put(key, bitmap);
    }
}

public Bitmap getBitmapFromMemCache( String key) {
    return mMemoryCache.get(key);
}</string,></string,>

As long as you ensure that the image resources of the entire APP are used through addBitmapToMemoryCache and getBitmapFromMemCache, OOM can be avoided.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326602390&siteId=291194637