LoadImage类:
package com.tarena.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import com.tarena.util.DiskLruCache.Editor;
import com.tarena.util.DiskLruCache.Snapshot;
import android.R.integer;
import android.R.string;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v4.util.LruCache;
import android.util.Log;
import android.widget.ImageView;
public class ImageLoader {
//下载完成任务执行完毕后发消息
public static final int LOAD_FINISH =102;
public static final int NEW_TASK =102;
//线程池中线程的数量、
//(这个数量应该与设备cpu的核数相同)
public static int Thread_Count;
//上下文
public static Context context;
//内存
public static LruCache<String, Bitmap> lruCache;
//双向队列,以后可以根据自己的需求选择对应的FIFO或者LIFO;
public static LinkedBlockingDeque<Runnable> blockingDeque;
//线程池
public static ExecutorService service;
//从任务队列中取下载人物的handler
public static Handler pollHandler;
//任务下载完毕后,用来刷新ListView条目显示下载图片内容
public static Handler uiHandler;
//养活PollHandler
public static Thread pollThread;
//标示的作用,用来确保ImageView只要进行一次赋值就可以。
public static boolean isFirstTiem = true;
//存储到sdcard当中
public static DiskLruCache diskLruCache;
public ImageLoader(){
}
/**
* 初始化所有属性的值
* @param context 上下文
*/
public static void inIt(Context context){
//初始化上下文
ImageLoader.context = context;
//初始化线程池中线程的数量
Thread_Count = getNumberOfCores();
//最大的缓存运行空间,内存缓存
lruCache = new LruCache<String, Bitmap>((int) (Runtime.getRuntime().maxMemory()/8)){
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getHeight()*value.getRowBytes();
}
};
//初始化磁盘缓存
try {
//参数是:第一个是文件存储的路径,第二个是项目版本号,一个Key对应几个Value,存储空间是多少
diskLruCache = DiskLruCache.open(directory(), appVersion(), 1, 1024*1024*20);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//初始化消息队列
blockingDeque = new LinkedBlockingDeque<Runnable>();
//初始化线程池
service = Executors.newFixedThreadPool(Thread_Count);
uiHandler = new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(Message msg) {
if (msg.what == LOAD_FINISH) {
ValueObject vObject = (ValueObject) msg.obj;
ImageView imageView = vObject.imageView;
String url = vObject.url;
Bitmap bitmap = vObject.bitmap;
if (imageView.getTag().toString().equals(url)) {
imageView.setImageBitmap(bitmap);
}
}else{
super.handleMessage(msg);
}
}
};
pollThread = new Thread(){
@Override
public void run() {
Looper.prepare();
pollHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
if (msg.what == NEW_TASK) {
try {
Runnable runnable = blockingDeque.takeFirst();
service.execute(runnable);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
super.handleMessage(msg);
}
}
};
Looper.loop();
}
};
pollThread.start();
isFirstTiem = false;
}
private static int appVersion() {
try {
//获取系统的项目的版本号
PackageInfo info = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
return info.versionCode;
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return 0;
}
private static File directory() {
String path = context.getExternalCacheDir().getPath();
return new File(path,"ImageLoaddercache");
}
/**
* 确定线程的数量
* @return
*/
public static int getNumberOfCores(){
File file = new File("/sys/devices/system/cpu/");
File[] files = file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String filename) {
if (filename.matches("cpu[0-9]")) {
return true;
}else{
return false;
}
}
});
if (files.length>0) {
return files.length;
}else{
return 1;
}
}
/**
*
* @param url
* @param imageView
*/
public static void loadImag(final String url,final ImageView imageView){
if (isFirstTiem) {
throw new RuntimeException("ImageLoad 未初始化");
}
//判断,url所指定的图像是否在缓存中有保存
//将url转换为MD5格式的字符串
Bitmap bitmap = lruCache.get(getMD5(url));
imageView.setTag(getMD5(url));
if (bitmap != null) {
Log.i("TAG", "图像是从内存缓存中加载的");
imageView.setImageBitmap(bitmap);
return;
}
//判断磁盘缓存中url所指定的图像是否在缓存中有保存
try {
Snapshot snap =diskLruCache.get(getMD5(url));
if (snap != null) {
InputStream inputStream = snap.getInputStream(0);
bitmap = BitmapFactory.decodeStream(inputStream);
//将从磁盘缓存中获得的图片放到内存缓存当中,下次还是直接去内存缓存
lruCache.put(getMD5(url), bitmap);
imageView.setImageBitmap(bitmap);
return;
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//内存缓存,磁盘缓存,当中都没有找到图片,就需要去网络中去获取图片
blockingDeque.add(new Runnable() {
@Override
public void run() {
try {
URL path = new URL(url);
HttpURLConnection connection = (HttpURLConnection) path.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setDoInput(true);
connection.connect();
InputStream inputStream = connection.getInputStream();
//要适当的压缩处理
Bitmap bitmap = compress(inputStream,imageView);
inputStream.close();
//将从网络获取并处理过后的图片,存到内存缓存,
lruCache.put(getMD5(url), bitmap);
//将从网络获取并处理过后的图片,存到磁盘缓存,
//构建一个Editor对象,
Editor editor = diskLruCache.edit(getMD5(url));
//获取输出流对象
OutputStream outputStream = editor.newOutputStream(0);
//设置图片的压缩格式
bitmap.compress(CompressFormat.JPEG, 100, outputStream);
//提交Editor进行存储
editor.commit();
//记录日志的方法
diskLruCache.flush();
/*
* 在给主线程发消息的时候,我要解决图片的重复加载问题,光传一个Bitmap是解决不了的
* 所以我要出一个ValueObject(imageview,图的Url,图);
*/
ValueObject object = new ValueObject(imageView, getMD5(url), bitmap);
//发消息到主线程,更新UI
Message.obtain(uiHandler, LOAD_FINISH,object).sendToTarget();
} catch (Exception e) {
e.printStackTrace();
}
}
});
Message.obtain(pollHandler,NEW_TASK).sendToTarget();
}
private static class ValueObject{
ImageView imageView ;
String url;
Bitmap bitmap;
public ValueObject(ImageView imageView, String url, Bitmap bitmap) {
super();
this.imageView = imageView;
this.url = url;
this.bitmap = bitmap;
}
}
/**
* 根据要显示的ImageView的大小对图像进行压缩
* @param inputStream
* @param imageView
* @return
*/
private static Bitmap compress(InputStream inputStream, ImageView imageView) {
Bitmap bitmap = null;
try {
//1)现货的图像源的尺寸大小
//借助Options来获得图像的大小
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte [] buff = new byte[4096];
int len = -1;
while ((len=inputStream.read(buff))!=-1) {
out.write(buff,0,len);
}
Options opts = new Options();
//如果设置了这句话,decodeByteArray返回值为Null;
opts.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(out.toByteArray(), 0, out.toByteArray().length,
opts);
int width = opts.outWidth;//图像的宽度(像素值)
int height = opts.outHeight;//图像的高度(像素值)
//在取ImageView的宽,高的时候。有的时候返回的是0
int targetWidth = imageView.getWidth();
int targetHeight = imageView.getHeight();
//所以要进行判断,解决这种的情况,有两种解决办法,
//可以手动制定宽,高
if (targetHeight == 0 || targetWidth == 0) {
//以当前设备的高度和宽度来作为压缩的依据
targetWidth = context.getResources().getDisplayMetrics().widthPixels;
targetHeight = context.getResources().getDisplayMetrics().heightPixels;
}
//计算压缩比
int sampleSize = 1;
//判断我去图片的宽,高去除我装图片的容器得到的值,如果大于1.
if (width*1.0 / targetWidth >1 || height*1.0/targetHeight>1) {
//就得到压缩比,他俩谁打取谁,记得要向上取整在转;
sampleSize = (int) Math.ceil(Math.max((width*1.0 / targetWidth), (height*1.0/targetHeight)));
}
//设置压缩比
opts.inSampleSize = sampleSize;
//设置返回值不为空
opts.inJustDecodeBounds = false;
//获得压缩后的图片
bitmap = BitmapFactory.decodeByteArray(out.toByteArray(), 0, out.toByteArray().length, opts);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
private static String getMD5(String url){
String result= "";
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
digest.update(url.getBytes());
byte [] bs = digest.digest();
StringBuilder sb = new StringBuilder();
for (byte b :bs) {
String str= Integer.toHexString(b & 0xff);
if (str.length() == 1) {
sb.append("0");
}
sb.append(str);
}
result = sb.toString();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
}