先说一下图片的三级缓存:首先肯定是内存缓存,接着是本地缓存(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;
}
}