Android 图片三级缓存

在Android开发中,我们经常会使用到网络图片资源,而为了避免频繁的访问网络获取图片资源,我们一般会将网络图片缓存到本地或者内存中以方便使用,这就需要使用到图片的三级缓存:

  1. 通过内存中获得图片
  2. 通过本地sd卡中获得图片
  3. 通过网络请求获得图片
通过使用"内存-本地文件-网络"这样的三级缓存策略,可以大大提高图片展示的效率,同时可以有效的避免图片oom异常的发生。

1. LruCache介绍

LruCache通过使用最近最少使用算法来维护内存缓存中缓存图片的数量,如果缓存达到指定的大小,LruCahe会自动将最近最少使用的图片移除缓存,把最新使用的图片加载内存中,这样可以始终让缓存中的图片维持在一定的数量上,同时可以避免oom异常的产生。在项目中我们只需要创建一个类继承自LruCache就可以实现缓存了。
代码如下:
/**
	 * 继承LruCache实现图片缓存
	 * 
	 * @author Administrator
	 * 
	 */
	class BitmapCache extends LruCache {
		public BitmapCache(int maxSize) {
			super(maxSize);
		}
		
		/**
		 * 返回图片的大小
		 */
		@Override
		protected int sizeOf(String key, Bitmap value) {
			return value.getByteCount();
		}
		
		
	}

	/**
	 * 私有构造函数
	 */
	private ImageCacheUtils(Context context) {
		mContext = context;
		// 初始化bitmapCache,获得系统可用的最大内存,并将可用内存的1/16作为图片缓存的大小,
		int maxMemory = (int) Runtime.getRuntime().maxMemory();
		int maxSize = maxMemory / 16;
		mBitmapCache = new BitmapCache(maxSize);
	}


2. 三级缓存的实现

代码如下:
package com.zk.imagecache;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Environment;
import android.support.v4.util.LruCache;

/**
 * 图片三级缓存实现 1、从内存中获得 2、从本地sd卡中获得 3、从网络中获得
 * 
 * @author Administrator
 * 
 */
public class ImageCacheUtils {
	/**
	 * 上下文
	 */
	private static Context mContext;
	/**
	 * 单例
	 */
	private static ImageCacheUtils mImageCacheUtils;

	/**
	 * 缓存bitmap
	 */
	private static BitmapCache mBitmapCache;

	/**
	 * 私有构造函数
	 */
	private ImageCacheUtils(Context context) {
		mContext = context;
		// 初始化bitmapCache,获得系统可用的最大内存,并将可用内存的1/16作为图片缓存的大小,
		int maxMemory = (int) Runtime.getRuntime().maxMemory();
		int maxSize = maxMemory / 16;
		mBitmapCache = new BitmapCache(maxSize);
	}

	/**
	 * 获得图片缓存对象
	 * 
	 * @param context
	 * @return
	 */
	public static ImageCacheUtils getInstance(Context context) {
		if (mImageCacheUtils == null) {
			mImageCacheUtils = new ImageCacheUtils(context);
		}
		return mImageCacheUtils;
	}

	/**
	 * 获得Bitmap对象
	 * 
	 * @param url
	 * @return
	 */
	public Bitmap getBitmap(String url) {
		// 将url地址的md5加密后的32位字符作为key,保证唯一性
		String key = SecurityUtils.MD5.get32MD5String(url);

		// 1、从内存中获得bitmap
		Bitmap bitmap = mBitmapCache.get(key);
		if (bitmap != null) {
			return bitmap;
		}

		// 2、内存中不存在该bitmap,从sd卡中获取
		bitmap = getDiskBitmap(key);
		if (bitmap != null) {
			return bitmap;
		}

		// 3、从网络中获得Bitmap
		bitmap = getNetBitmap(url);
		if (bitmap != null) {
			return bitmap;
		}
		return null;
	}

	/**
	 * 将图片保存到内存中
	 * 
	 * @param url
	 * @param bitmap
	 */
	private void saveBitmap(String key, Bitmap bitmap) {
		if (mBitmapCache.get(key) == null) {
			mBitmapCache.put(key, bitmap);
		}
	}

	/**
	 * 从sd卡中获得图片
	 * 
	 * @param key
	 * @return
	 */
	private Bitmap getDiskBitmap(String key) {
		try {
			File file = getDiskFile(key);
			if (file.exists()) {
				FileInputStream fis = new FileInputStream(file);
				Bitmap bitmap = BitmapFactory.decodeStream(fis);
				// 加载到内存中
				mBitmapCache.put(key, bitmap);
				return bitmap;
			}
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		return null;
	}

	/**
	 * 将图片保存到sd卡中
	 * 
	 * @param key
	 */
	private void saveDiskBitmap(String key, Bitmap bitmap) {
		try {
			File file = getDiskFile(key);
			file.createNewFile();
			FileOutputStream fos = new FileOutputStream(file);
			Bitmap.createScaledBitmap(bitmap, bitmap.getWidth(),
					bitmap.getHeight(), true);
			bitmap.compress(CompressFormat.PNG, 100, fos);
			fos.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获得sd卡存储图片路径
	 * 
	 * @param url
	 * @return
	 */
	private File getDiskFile(String key) {
		String path = "";
		String externalStorageState = Environment.getExternalStorageState();
		if (Environment.MEDIA_MOUNTED.equals(externalStorageState)) {
			path = Environment.getExternalStorageDirectory().getAbsolutePath();
		} else {
			path = mContext.getCacheDir().getAbsolutePath();
		}
		// 获得图片文件
		File dirFile = new File(path + "/imagecache");
		if (!dirFile.exists()) {
			dirFile.mkdirs();
		}
		File file = new File(dirFile, key + ".png");
		return file;
	}

	/**
	 * 从网络中获得图片
	 * 
	 * @param url
	 */
	private Bitmap getNetBitmap(String url) {
		try {
			// 创建一个线程池
			ExecutorService pool = Executors.newCachedThreadPool();
			Future future = pool.submit(new BitmapCallable(url));
			Bitmap bitmap = future.get();
			pool.shutdown();

			// Bitmap bitmap = new BitmapTask().execute(url).get();
			return bitmap;
		} catch (Exception e) {
			e.printStackTrace();
		}

		return null;
	}

	/**
	 * callable线程
	 * 
	 * @author Administrator
	 * 
	 */
	class BitmapCallable implements Callable {
		private String path;

		public BitmapCallable(String path) {
			this.path = path;
		}

		@Override
		public Bitmap call() throws Exception {
			HttpClient client = new DefaultHttpClient();
			HttpGet httpPost = new HttpGet(path);
			HttpResponse response = client.execute(httpPost);
			int statusCode = response.getStatusLine().getStatusCode();
			if (statusCode == 200) {
				InputStream inputStream = response.getEntity().getContent();
				Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
				if (bitmap != null) {
					String key = SecurityUtils.MD5.get32MD5String(path);
					// 保存到内存
					saveBitmap(key, bitmap);
					// 保存到sd卡
					saveDiskBitmap(key, bitmap);
				}
				inputStream.close();
				return bitmap;
			}
			return null;
		}

	}

	class BitmapTask extends AsyncTask {

		@Override
		protected Bitmap doInBackground(String... params) {
			try {
				String path = params[0];
				URL url = new URL(path);
				HttpURLConnection conn = (HttpURLConnection) url
						.openConnection();
				conn.setRequestMethod("GET");
				conn.setConnectTimeout(5000);
				InputStream inputStream = conn.getInputStream();
				Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
				if (bitmap != null) {
					String key = SecurityUtils.MD5.get32MD5String(path);
					// 保存到内存
					saveBitmap(key, bitmap);
					// 保存到sd卡
					saveDiskBitmap(key, bitmap);
				}
				inputStream.close();
				return bitmap;

			} catch (Exception e) {
				e.printStackTrace();
			}

			return null;
		}

		@Override
		protected void onPostExecute(Bitmap result) {
			super.onPostExecute(result);
		}

	}

	/**
	 * 继承LruCache实现图片缓存
	 * 
	 * @author Administrator
	 * 
	 */
	class BitmapCache extends LruCache {
		public BitmapCache(int maxSize) {
			super(maxSize);
		}
		
		/**
		 * 返回图片的大小
		 */
		@Override
		protected int sizeOf(String key, Bitmap value) {
			return value.getByteCount();
		}
		
		
	}

}

具体调用:
mBtnShow = (Button) findViewById(R.id.btn_show);
		mIvShow = (ImageView) findViewById(R.id.iv_show);

		mBtnShow.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				mIvShow.setImageBitmap(ImageCacheUtils
						.getInstance(MainActivity.this)
						.getBitmap(
								"https://img-my.csdn.net/uploads/201407/26/1406383213_3557.jpg"));
			}
		});

效果图:
Android 图片三级缓存_第1张图片


源码下载





你可能感兴趣的:(Android,基础总结)