Hi all

This example shows you how to load large images in the gridview without any lag or without outofmemory error.

Fast Grid

This sample application uses the LruCache to hold the images.

A cache that holds strong references to a limited number of values. Each time a value is accessed, it is moved to the head of a queue. When a value is added to a full cache, the value at the end of that queue is evicted and may become eligible for garbage collection.

Read more from here.

http://developer.android.com/reference/android/util/LruCache.html

Now we will go to the implementation.

This is the MainActivity that holds the GridView.
We are adding here 100 images in the Grid to load.
This time I am loading images from the resources.

Everything is explained with in the code itself, So I am not adding more description here

MainActivity.java

package com.coderzheaven.testlistview;

import java.util.ArrayList;

import android.app.Activity;
import android.os.Bundle;
import android.widget.GridView;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);

		ArrayList<String> items = new ArrayList<String>();

		// adding 100 images
		for (int p = 0; p < 100; p++) {
			items.add("photo");
		}

		ListAdapter list = new ListAdapter(this, items);

		GridView grid = new GridView(this);

		grid.setAdapter(list);

		grid.setNumColumns(GridView.AUTO_FIT);

		setContentView(grid);

	}

}

OK Now that our Activity is complete we will see the ListAdapter class that is processing each image and helps loading fast.

ListAdapter.java

package com.coderzheaven.testlistview;

import java.lang.ref.WeakReference;
import java.util.ArrayList;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.util.LruCache;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridLayout.LayoutParams;
import android.widget.GridView;
import android.widget.ImageView;

public class ListAdapter extends BaseAdapter {

	Context context;
	ArrayList<String> items;
	private LruCache<String, Bitmap> mMemoryCache;

	public ListAdapter(Context context, ArrayList<String> items) {
		this.context = context;
		this.items = items;

		// Get memory class of this device, exceeding this amount will throw an
		// OutOfMemory exception.
		final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

		// Use 1/8th of the available memory for this memory cache.
		final int cacheSize = maxMemory / 8;

		mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {

			protected int sizeOf(String key, Bitmap bitmap) {
				// The cache size will be measured in bytes rather than number
				// of items.
				return bitmap.getByteCount();
			}

		};
	}

	@Override
	public int getCount() {
		return items.size();
	}

	@Override
	public Object getItem(int arg0) {
		return items.get(arg0);
	}

	@Override
	public long getItemId(int arg0) {
		return arg0;
	}

	@Override
	public View getView(int arg0, View convertView, ViewGroup arg2) {
		ImageView img = null;

		if (convertView == null) {
			img = new ImageView(context);
			img.setScaleType(ImageView.ScaleType.CENTER_CROP);
			img.setLayoutParams(new GridView.LayoutParams(
					LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
		} else {
			img = (ImageView) convertView;
		}

		int resId = context.getResources().getIdentifier(items.get(arg0),
				"drawable", context.getPackageName());

		loadBitmap(resId, img);

		return img;
	}

	public void loadBitmap(int resId, ImageView imageView) {
		if (cancelPotentialWork(resId, imageView)) {
			final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
			imageView.setBackgroundResource(R.drawable.empty_photo);
			task.execute(resId);
		}
	}

	static class AsyncDrawable extends BitmapDrawable {
		private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;

		public AsyncDrawable(Resources res, Bitmap bitmap,
				BitmapWorkerTask bitmapWorkerTask) {
			super(res, bitmap);
			bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>(
					bitmapWorkerTask);
		}

		public BitmapWorkerTask getBitmapWorkerTask() {
			return bitmapWorkerTaskReference.get();
		}
	}

	public static boolean cancelPotentialWork(int data, ImageView imageView) {
		final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);

		if (bitmapWorkerTask != null) {
			final int bitmapData = bitmapWorkerTask.data;
			if (bitmapData != data) {
				// Cancel previous task
				bitmapWorkerTask.cancel(true);
			} else {
				// The same work is already in progress
				return false;
			}
		}
		// No task associated with the ImageView, or an existing task was
		// cancelled
		return true;
	}

	private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
		if (imageView != null) {
			final Drawable drawable = imageView.getDrawable();
			if (drawable instanceof AsyncDrawable) {
				final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
				return asyncDrawable.getBitmapWorkerTask();
			}
		}
		return null;
	}

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

	public Bitmap getBitmapFromMemCache(String key) {
		return (Bitmap) mMemoryCache.get(key);
	}

	class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
		public int data = 0;
		private final WeakReference<ImageView> imageViewReference;

		public BitmapWorkerTask(ImageView imageView) {
			// Use a WeakReference to ensure the ImageView can be garbage
			// collected
			imageViewReference = new WeakReference<ImageView>(imageView);
		}

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

		// Once complete, see if ImageView is still around and set bitmap.
		@Override
		protected void onPostExecute(Bitmap bitmap) {
			if (imageViewReference != null && bitmap != null) {
				final ImageView imageView = imageViewReference.get();
				if (imageView != null) {
					imageView.setImageBitmap(bitmap);
				}
			}
		}
	}

	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) {

			// Calculate ratios of height and width to requested height and
			// width
			final int heightRatio = Math.round((float) height
					/ (float) reqHeight);
			final int widthRatio = Math.round((float) width / (float) reqWidth);

			// Choose the smallest ratio as inSampleSize value, this will
			// guarantee
			// a final image with both dimensions larger than or equal to the
			// requested height and width.
			inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
		}

		return inSampleSize;
	}

}

You can download the sample android source code from here.

Please leave your comments. I will be adding a modified version of this sample for using it to download from a URL and caching it in the disk and Memory in the coming posts.

 

12 Comments

  1. Dilsha September 5, 2013 at 10:01 am

    Please give your email id.

     
  2. Stella March 1, 2014 at 4:27 pm

    Thanks for your sample code!
    Could you please also post the modified version of this sample with images being downloaded from a URL?
    I tried modified the code myself to display images from URL but no luck 🙁

     
    • James March 2, 2014 at 4:24 pm

      There are similar codes in Coderzheaven.com. Please search that.

       
      • Eric March 27, 2014 at 8:47 am

        Haven’t found one but would be really grateful if the modified version will posted. 🙂

         
  3. Denis March 29, 2014 at 6:57 pm

    Thank you for this code, it helped me!

     
  4. Kei June 4, 2014 at 1:20 am

    So, how the cached image is used? getBitmapFromMemCache is only called from addBitmapToMemoryCache.

     
    • 0k4pix July 6, 2014 at 1:21 pm

      This code isn’t complete.
      As Kei said, no cached bitmap is loaded…
      So add this code:

      protected Bitmap doInBackground(Integer… params) {
      poster_id = params[0];
      Poster p;
      try {
      Bitmap bmp_cached = getBitmapFromMemoryCache(String.valueOf(poster_id));
      if(bmp_cached == null)
      {
      //DECODE YOUR BITMAP
      bmp = Bitmap.createScaledBitmap(bmp, width, height, true);
      addBitmapToMemoryCache(String.valueOf(poster_id), bmp);
      }
      else
      bmp = bmp_cached;

      return bmp;

      } catch (Exception e) {
      }

       
  5. Sachin September 11, 2015 at 10:03 am

    Can any one help me, how to cache the phone book contact list?

     
    • James March 13, 2017 at 9:15 am

      Sachin, You can use Sqlite to cache values in a table or you can use some array list to cache.

       
  6. Deepika March 21, 2017 at 7:18 am

    images are not displaying in my gridview after trying above code

     
    • James March 23, 2017 at 5:52 am

      Deepika,

      Make sure you have working image url and and a working internet connection. Don’t forget to add internet permission in the manifest.

       

Leave a Reply

Your email address will not be published. Required fields are marked *

 

 

 

Theme by HermesThemes

Copyright © 2018 CoderzHeaven. All Rights Reserved

Please wait...

Subscribe to our newsletter

Want to be notified when our article is published? Enter your email address and name below to be the first to know.