Android image loading Optimization

Source: Internet
Author: User

Android applications frequently process images. Especially when a program loads a large number of images and high-resolution images, oom exceptions are most likely to occur. Below are some of my memory loading methods.

Method 1:

public Bitmap decodeFile(String filePath) {Bitmap bitmap = null;BitmapFactory.Options options = new BitmapFactory.Options();options.inPurgeable = true;try {BitmapFactory.Options.class.getField("inNativeAlloc").setBoolean(options, true);} catch (IllegalArgumentException e) {e.printStackTrace();} catch (SecurityException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();}if (mFilePath != null) {bitmap = BitmapFactory.decodeFile(mFilePath, options);}return bitmap;}

Method 2:

Public bitmap readbitmap (context, int resid) {bitmapfactory. options opt = new bitmapfactory. options (); OPT. inpreferredconfig = bitmap. config. rgb_565; OPT. inpurgeable = true; OPT. ininputtransferable = true; // obtain the resource image inputstream is = context. getresources (). openrawresource (resid); Return bitmapfactory. decodestream (is, null, OPT );}

Now you know the size of the original image, and decide how many times it will be loaded according to the actual situation. For example, if you use a x 96 imageview to display a x source image, there is no need to read the source image to the memory.
To load a reduced image to the memory, set the insamplesize of the bitmapfactory. Options object to true,
Set a value for insamplesize (it can be understood that insamplesize is N, and the image size is reduced to 1/n ).

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,          int reqWidth, int reqHeight) {        // First decode with inJustDecodeBounds=true to check dimensions      final BitmapFactory.Options options = new BitmapFactory.Options();      options.inJustDecodeBounds = true;      BitmapFactory.decodeResource(res, resId, options);        // Calculate inSampleSize      options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);        // Decode bitmap with inSampleSize set      options.inJustDecodeBounds = false;      return BitmapFactory.decodeResource(res, resId, options);  }  public static int calculateInSampleSize(              BitmapFactory.Options options, int reqWidth, int reqHeight) {      // Raw height and width of image      final int height = options.outHeight;      final int width = options.outWidth;      int inSampleSize = 1;        if (height > reqHeight || width > reqWidth) {          if (width > height) {              inSampleSize = Math.round((float)height / (float)reqHeight);          } else {              inSampleSize = Math.round((float)width / (float)reqWidth);          }      }      return inSampleSize;  }  

Method 3: Use the memory cache

No cache size or rules apply to all applications. It relies on you to analyze the memory usage of your applications and determine your own solution.
If the cache is too small, it may only increase the memory usage. If the cache is too large, it may cause memory overflow or other modules may use too small memory.

private LruCache mMemoryCache;    @Override  protected void onCreate(Bundle savedInstanceState) {      ...      // Get memory class of this device, exceeding this amount will throw an      // OutOfMemory exception.      final int memClass = ((ActivityManager) context.getSystemService(              Context.ACTIVITY_SERVICE)).getMemoryClass();        // Use 1/8th of the available memory for this memory cache.      final int cacheSize = 1024 * 1024 * memClass / 8;        mMemoryCache = new LruCache(cacheSize) {          @Override          protected int sizeOf(String key, Bitmap bitmap) {              // The cache size will be measured in bytes rather than number of items.              return bitmap.getByteCount();          }      };      ...  }    public void addBitmapToMemoryCache(String key, Bitmap bitmap) {      if (getBitmapFromMemCache(key) == null) {          mMemoryCache.put(key, bitmap);      }  }    public Bitmap getBitmapFromMemCache(String key) {      return mMemoryCache.get(key);  }  public void loadBitmap(int resId, ImageView imageView) {      final String imageKey = String.valueOf(resId);        final Bitmap bitmap = getBitmapFromMemCache(imageKey);      if (bitmap != null) {          mImageView.setImageBitmap(bitmap);      } else {          mImageView.setImageResource(R.drawable.image_placeholder);          BitmapWorkerTask task = new BitmapWorkerTask(mImageView);          task.execute(resId);      }  }  

After bitmapworkertask loads an image, it also needs to cache the image to the memory:

class BitmapWorkerTask extends AsyncTask {      ...      // Decode image in background.      @Override      protected Bitmap doInBackground(Integer... params) {          final Bitmap bitmap = decodeSampledBitmapFromResource(                  getResources(), params[0], 100, 100));          addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);          return bitmap;      }      ...  }  

Method 4: Use disk cache

Your application may also be interrupted by other tasks, such as incoming calls. The application may be terminated in the background, and cached data may also be lost.
When the user returns to the application, all the images need to be retrieved again.
The disk cache can be applied to this scenario. It can reduce the number of times you obtain images. Of course, obtaining images from a disk is much slower than obtaining images from the memory, therefore, it must be completed in a non-UI thread.
The sample code is an implementation of disk cache. In the android4.0 source code (libcore/luni/src/main/Java/libcore/IO/disklrucache. Java ),
There is a much more enhanced and recommended implementation. Its Backward compatibility makes it easy to use in published libraries.

private DiskLruCache mDiskCache;private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MBprivate static final String DISK_CACHE_SUBDIR = "thumbnails";@Overrideprotected void onCreate(Bundle savedInstanceState) {    ...    // Initialize memory cache    ...    File cacheDir = getCacheDir(this, DISK_CACHE_SUBDIR);    mDiskCache = DiskLruCache.openCache(this, cacheDir, DISK_CACHE_SIZE);    ...}class BitmapWorkerTask extends AsyncTask {    ...    // Decode image in background.    @Override    protected Bitmap doInBackground(Integer... params) {        final String imageKey = String.valueOf(params[0]);        // Check disk cache in background thread        Bitmap bitmap = getBitmapFromDiskCache(imageKey);        if (bitmap == null) { // Not found in disk cache            // Process as normal            final Bitmap bitmap = decodeSampledBitmapFromResource(                    getResources(), params[0], 100, 100));        }        // Add final bitmap to caches        addBitmapToCache(String.valueOf(imageKey, bitmap);        return bitmap;    }    ...}public void addBitmapToCache(String key, Bitmap bitmap) {    // Add to memory cache as before    if (getBitmapFromMemCache(key) == null) {        mMemoryCache.put(key, bitmap);    }    // Also add to disk cache    if (!mDiskCache.containsKey(key)) {        mDiskCache.put(key, bitmap);    }}public Bitmap getBitmapFromDiskCache(String key) {    return mDiskCache.get(key);}// Creates a unique subdirectory of the designated app cache directory. Tries to use external// but if not mounted, falls back on internal storage.public static File getCacheDir(Context context, String uniqueName) {    // Check if media is mounted or storage is built-in, if so, try and use external cache dir    // otherwise use internal cache dir    final String cachePath = Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED            || !Environment.isExternalStorageRemovable() ?                    context.getExternalCacheDir().getPath() : context.getCacheDir().getPath();    return new File(cachePath + File.separator + uniqueName);}

Configuration changes during running. For example, if the screen has a good user experience, you may not want to re-obtain the image in this case.
Fortunately, you can use the memory cache mentioned above. Cache can be uploaded to a new activity by using a fragment (call setretaininstance (true,
After a new activity is created, you only need to re-append the fragment to get the fragment and access the existing cache to quickly display the images in it.

private LruCache mMemoryCache;@Overrideprotected void onCreate(Bundle savedInstanceState) {    ...    RetainFragment mRetainFragment =            RetainFragment.findOrCreateRetainFragment(getFragmentManager());    mMemoryCache = RetainFragment.mRetainedCache;    if (mMemoryCache == null) {        mMemoryCache = new LruCache(cacheSize) {            ... // Initialize cache here as usual        }        mRetainFragment.mRetainedCache = mMemoryCache;    }    ...}class RetainFragment extends Fragment {    private static final String TAG = "RetainFragment";    public LruCache mRetainedCache;    public RetainFragment() {}    public static RetainFragment findOrCreateRetainFragment(FragmentManager fm) {        RetainFragment fragment = (RetainFragment) fm.findFragmentByTag(TAG);        if (fragment == null) {            fragment = new RetainFragment();        }        return fragment;    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setRetainInstance(true);    }}

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.