先说一下图片的三级缓存:首先肯定是内存缓存,接着是本地缓存(SD卡),网络缓存。
再来看一看图片缓存的流程图:
下面上代码:代码中用到了线程池、还有内存中的软引用
import java.io.IOException; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import android.content.Context; import android.graphics.Bitmap; import android.os.Handler; import android.os.Message; import android.support.v4.util.LruCache; import android.widget.ImageView; /** * @version 1.0 * @创建时间:2014-8-5 下午5:41:03 * */ public class ImageDownLoader { private static final int LOAD_SUCCESS = 1; /** 缓存Image的类,当存储Image的大小大于LruCache设定的值,系统自动释放内存 */ private LruCache<String, Bitmap> lruCache; /** 文件操作工具类 */ private FileUtils utils; private ThreadPoolExecutor executor; public ImageDownLoader(Context context) { super(); // 开启线程池 最小线程数 executor = new ThreadPoolExecutor(1, 4, 2, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>()); // 获取系统分配给应用程序的最大内存 int maxMemory = (int) Runtime.getRuntime().maxMemory(); int maxSize = maxMemory / 8; lruCache = new LruCache<String, Bitmap>(maxSize) { @Override protected int sizeOf(String key, Bitmap value) { // 测量Bitmap的大小 默认返回图片数量 return value.getRowBytes() * value.getHeight(); } }; utils = new FileUtils(context); } /** * * @Title: downLoader * @说 明: 加载图片 * @参 数: @param url * @参 数: @param loaderlistener * @参 数: @return * @return Bitmap 返回类型 * @throws */ public Bitmap downLoader(final ImageView imageView, final ImageLoaderlistener loaderlistener) { final String url = (String) imageView.getTag(); //首先得到图片设置的tag(用来区分图片错位的情况),所以在调用此类<span style="white-space:pre"> </span> //之前,应该给ImageView控件设置Tag if (url != null) { final Bitmap bitmap = showCacheBitmap(url);//这里就是从缓存中去找图片 if (bitmap != null) { //如果缓存中返回的图片为空的,则开启线程进行下载 return bitmap; } else { final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); loaderlistener.onImageLoader((Bitmap) msg.obj, imageView); } }; executor.execute(new Runnable() { @Override public void run() { Bitmap bitmap = HttpUtils.getBitmapFormUrl(url); if (bitmap != null) { //下载完毕之后将图片保存到缓存和本地,然后通知ImageView更新UI Message msg = handler.obtainMessage(); msg.obj = bitmap; msg.what = LOAD_SUCCESS; handler.sendMessage(msg); try { utils.savaBitmap(url, bitmap); } catch (IOException e) { e.printStackTrace(); } lruCache.put(url, bitmap); } } }); } } return null; } /** * * @Title: showCacheBitmap * @说 明: 获取bitmap对象 : 内存中没有就去sd卡中去找 * @参 数: @param url 图片地址 * @参 数: @return * @return Bitmap 返回类型 图片 * @throws */ public Bitmap showCacheBitmap(String url) { Bitmap bitmap = getMemoryBitmap(url); if (bitmap != null) { return bitmap; } else if (utils.isFileExists(url) && utils.getFileSize(url) > 0) { bitmap = utils.getBitmap(url); lruCache.put(url, bitmap); return bitmap; } return null; } /** * * @Title: getMemoryBitmap * @说 明:获取内存中的图片 * @参 数: @param url * @参 数: @return * @return Bitmap 返回类型 * @throws */ private Bitmap getMemoryBitmap(String url) { return lruCache.get(url); } public interface ImageLoaderlistener { public void onImageLoader(Bitmap bitmap,ImageView imageView); } /** * * @Title: cancelTask * @说 明:停止所有下载线程 * @参 数: * @return void 返回类型 * @throws */ public void cancelTask() { if (executor != null) { executor.shutdownNow(); } } }
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import android.os.Environment; public class FileUtils { /** * sd卡的根目录 */ private static String mSdRootPath = Environment.getExternalStorageDirectory().getPath(); /** * 手机的缓存根目录 */ private static String mDataRootPath = null; /** * 保存Image的目录名 */ private final static String FOLDER_NAME = "/tea/image"; public FileUtils(Context context) { mDataRootPath = context.getCacheDir().getPath(); } /** * 获取储存Image的目录 * * @return */ private String getStorageDirectory() { return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ? mSdRootPath + FOLDER_NAME : mDataRootPath + FOLDER_NAME; } /** * 保存Image的方法,有sd卡存储到sd卡,没有就存储到手机目录 * * @param fileName * @param bitmap * @throws IOException */ public void savaBitmap(String url, Bitmap bitmap) throws IOException { if (bitmap == null) { return; } String path = getStorageDirectory(); File folderFile = new File(path); if (!folderFile.exists()) { folderFile.mkdirs(); } File file = new File(path + File.separator + getFileName(url)); file.createNewFile(); FileOutputStream fos = new FileOutputStream(file); bitmap.compress(CompressFormat.JPEG, 100, fos); fos.flush(); fos.close(); } /** * 从手机或者sd卡获取Bitmap * * @param fileName * @return */ public Bitmap getBitmap(String url) { return BitmapFactory.decodeFile(getStorageDirectory() + File.separator + getFileName(url)); } /** * 判断文件是否存在 * * @param fileName * @return */ public boolean isFileExists(String fileName) { return new File(getStorageDirectory() + File.separator + getFileName(fileName)).exists(); } /** * 获取文件的大小 * * @param fileName * @return */ public long getFileSize(String url) { return new File(getStorageDirectory() + File.separator + getFileName(url)).length(); } /** * 删除SD卡或者手机的缓存图片和目录 */ public void deleteFile() { File dirFile = new File(getStorageDirectory()); if (!dirFile.exists()) { return; } if (dirFile.isDirectory()) { String[] children = dirFile.list(); for (int i = 0; i < children.length; i++) { new File(dirFile, children[i]).delete(); } } dirFile.delete(); } /** * * @Title: getFileName * @说 明: 根据url截取文件名 * @参 数: @param url * @参 数: @return * @return String 返回类型 * @throws */ public String getFileName(String url) { return url.substring(url.lastIndexOf("/") + 1); } } -------------------------------------------下载工具类------------------------------------------------------------------- package com.qianfeng.android.utils; import java.io.IOException; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.params.HttpClientParams; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import org.apache.http.util.EntityUtils; import android.graphics.Bitmap; import android.graphics.BitmapFactory; public class HttpUtils { /** * * @Title: getBitmapFormUrl * @说 明:从服务器获取Bitmap * @参 数: @param url * @参 数: @return * @return Bitmap 返回类型 * @throws */ public static Bitmap getBitmapFormUrl(String url) { Bitmap bitmap = null; HttpClient httpClient = new DefaultHttpClient(); // 设置超时时间 HttpConnectionParams.setConnectionTimeout(new BasicHttpParams(), 6 * 1000); HttpGet get = new HttpGet(url); try { HttpResponse response = httpClient.execute(get); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { HttpEntity entity = response.getEntity(); bitmap = BitmapFactory.decodeStream(entity.getContent()); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return bitmap; } public static String getJsonFromServer(String url) { HttpClient httpClient = getHttpClient(); HttpGet get = new HttpGet(url); try { HttpResponse response = httpClient.execute(get); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { HttpEntity entity = response.getEntity(); return EntityUtils.toString(entity); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (get != null) { get.abort(); } } return null; } /** * * @Title: getHttpClient * @说 明:设置httpClient的一些参数 * @参 数: @return * @return HttpClient 返回类型 * @throws */ private static HttpClient getHttpClient() { // 创建 HttpParams 以用来设置 HTTP 参数(这一部分不是必需的) HttpParams httpParams = new BasicHttpParams(); // 设置连接超时和 Socket 超时,以及 Socket 缓存大小 HttpConnectionParams.setConnectionTimeout(httpParams, 20 * 1000); HttpConnectionParams.setSoTimeout(httpParams, 20 * 1000); HttpConnectionParams.setSocketBufferSize(httpParams, 8192); // 设置重定向,缺省为 true HttpClientParams.setRedirecting(httpParams, true); // 设置 user agent String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2) Gecko/20100115 Firefox/3.6"; HttpProtocolParams.setUserAgent(httpParams, userAgent); // 创建一个 HttpClient 实例 // 注意 HttpClient httpClient = new HttpClient(); 是Commons HttpClient // 中的用法,在 Android 1.5 中我们需要使用 Apache 的缺省实现 DefaultHttpClient HttpClient httpClient = new DefaultHttpClient(httpParams); return httpClient; } }