import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;import java.io.StringWriter;import java.util.HashMap;import java.util.Iterator;import java.util.LinkedList;import java.util.concurrent.Executor;import java.util.concurrent.Executors;import org.apache.http.HttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.DefaultHttpClient;import org.json.JSONException;import org.json.JSONObject;import android.content.Context;import android.net.Uri;import android.os.Environment;import android.os.Handler;import android.os.Message;import android.util.Log;import android.widget.ImageSwitcher;import android.widget.ImageView;/** * 图片加载帮助类(自动异步加载、图片文件缓存、缓存文件管理) * * @author n.zhang * */public class ImageLoad { private static final String TAG = "imageLoad";// 日志标签 private static final String TAG_REF = TAG + "Ref"; private Executor executor; // 线程池 private int defaultImageID;// 默认图片id private Context context;// 你懂的 private HashMap<String, PathInfo> cache = new HashMap<String, PathInfo>();// URL boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED); // 路径信息对应表 private LinkedList<PathInfo> use = new LinkedList<PathInfo>();// 已在使用的路径信息队列 private LinkedList<PathInfo> lost = new LinkedList<PathInfo>();// 还未使用的路径信息队列 private LinkedList<PathInfo> original = new LinkedList<PathInfo>();// 初始图片路径信息队列 private int index = 0;// id下标 /** * 图片加载工具,默认10线程下载,缓存80张图片 * * @param context */ public ImageLoad(Context context) { this(context, 10, 80, 0); } /** * 图片加载工具 * * @param context * 你懂的 * @param threadSize * 最大线程数 * @param maxCacheSize * 最大缓存图片数量 * @param defaultImageID * 默认图片id */ public ImageLoad(Context context, int threadSize, int maxCacheSize, int defaultImageID) { this.context = context; this.defaultImageID = defaultImageID; executor = Executors.newFixedThreadPool(threadSize); loadImagePathInfo(); // 图片信息数量不足不满最大值,以空白图片信息补足。 newImagePathInfo(maxCacheSize); for (PathInfo pi : original) { if (null == pi.url) { lost.offer(pi); } else { use.offer(pi); cache.put(pi.url, pi); } } File dir = null; if (sdCardExist) { dir = new File(Environment.getExternalStorageDirectory() + "/t_image/"); } else { dir = new File(context.getCacheDir() + "/t_image/"); } // 如果文件存在并且不是目录,则删除 if (dir.exists() && !dir.isDirectory()) { dir.delete(); } // 如果目录不存在,则创建 if (!dir.exists()) { dir.mkdir(); } } /** * 路径信息 * * @author n.zhang * */ public static class PathInfo { private int id;// 图片id 此id用于生成存储图片的文件名。 private String url;// 图片url } /** * 获得图片存储路径 * * @param url * @return */ public PathInfo getPath(String url) { PathInfo pc = cache.get(url); if (null == pc) { pc = lost.poll(); } if (null == pc) { pc = use.poll(); refresh(pc); } return pc; } /** * @info 微博使用加载数据路径 * @author FFMobile-cuihe * @date 2012-3-1 下午2:13:10 * @Title: getsPath * @Description: TODO * @param@param url * @param@return 设定文件 * @return PathInfo 返回类型 * @throws */ public PathInfo getsPath(String url) { PathInfo pc = cache.get(url); if (null == pc) { pc = lost.peek(); } // if (null == pc) { // pc = use.peek(); // refresh(pc); // } return pc; } public PathInfo getLocalPath(String url) { PathInfo pc = cache.get(url); if (null == pc) { pc = lost.peek(); } return pc; } /** * 刷新路径信息(从索引中删除对应关系、删除对应的图片文件、获取一个新id) * * @param pc */ private void refresh(PathInfo pc) { long start = System.currentTimeMillis(); File logFile = null; try { cache.remove(pc.url); File file = toFile(pc); file.delete(); logFile = file; pc.id = index++; pc.url = null; } finally { Log.d(TAG_REF, "ref time {" + (System.currentTimeMillis() - start) + "}; ref {" + logFile + "}"); } } /** * 获得file对象 * * @param pi * 路径缓存 * @return */ public File toFile(PathInfo pi) { if (sdCardExist) { return new File(Environment.getExternalStorageDirectory() + "/t_image/" + pi.id + ".jpg"); } else { return new File(context.getCacheDir() + "/t_image/" + pi.id + ".jpg"); } } /** * 请求加载图片 * * @param url * @param ilCallback */ public void request(String url, final ILCallback ilCallback) { final long start = System.currentTimeMillis(); final PathInfo pc = getPath(url); File file = toFile(pc); if (null != pc.url) { ilCallback.seed(Uri.fromFile(file)); Log.d(TAG, "load time {" + (System.currentTimeMillis() - start) + "}; cache {" + pc.url + "} "); } else { pc.url = url; Handler mHandler = new Handler() { public void handleMessage(Message msg) { if (null == msg.obj) { ilCallback.seed(Uri.EMPTY); Log.d(TAG, "load lost time {" + (System.currentTimeMillis() - start) + "}; network lost {" + pc.url + "}"); } else { ilCallback.seed((Uri) msg.obj); Log.d(TAG, "load time {" + (System.currentTimeMillis() - start) + "}; network {" + pc.url + "}"); } }; }; executor.execute(new DownloadImageTask(pc, file, mHandler)); } } private void localRequest(String url, final ILCallback ilCallback) { final long start = System.currentTimeMillis(); final PathInfo pc = getLocalPath(url); File file = toFile(pc); if (null != pc.url) { ilCallback.seed(Uri.fromFile(file)); Log.d(TAG, "load time {" + (System.currentTimeMillis() - start) + "}; cache {" + pc.url + "} "); } } public void localRequest(String url, ImageView iv) { localRequest(url, new ImageViewCallback(iv)); } /** * 请求加载图片 * * @param url * @param iv */ public void request(String url, ImageView iv) { request(url, new ImageViewCallback(iv)); } /** * 请求加载图片 * * @param url * @param iv */ // public void request(String url, ImageButton iv) { // request(url, new ImageButtonCallbacks(iv)); // } /** * 请求加载图片 * * @param url * @param iv */ // public void request(String url, Button iv) { // request(url, new ButtonCallbacks(iv)); // } /** * 请求加载图片 * * @param url * @param iv */ public void request(String url, ImageSwitcher iv) { request(url, new ImageSwitcherCallbacks(iv)); } /** * 下载图片任务 * * @author Administrator * */ private class DownloadImageTask implements Runnable { private Handler hc; private PathInfo pi; private File file; public DownloadImageTask(PathInfo pi, File file, Handler hc) { this.pi = pi; this.file = file; this.hc = hc; } public void run() { try { byte[] b = requestHttp(pi.url); if (null == b) { throw new IOException("数据为空"); } writeFile(file, b); use.offer(pi); cache.put(pi.url, pi); Message message = new Message(); message.obj = Uri.fromFile(file); hc.sendMessage(message); } catch (IOException e) { Message message = hc.obtainMessage(0, Uri.EMPTY); hc.sendMessage(message); Log.i(TAG, "image download lost.", e); } catch (RuntimeException e) { Message message = hc.obtainMessage(0, Uri.EMPTY); hc.sendMessage(message); Log.i(TAG, "image download lost.", e); } } } private void writeFile(File file, byte[] data) throws IOException { FileOutputStream out = new FileOutputStream(file); try { out.write(data); } finally { out.close(); } } private static byte[] requestHttp(String url) throws IOException { DefaultHttpClient client = new DefaultHttpClient(); System.gc(); try { HttpGet get = new HttpGet(url); HttpResponse res = client.execute(get); ByteArrayOutputStream baos = new ByteArrayOutputStream(); if (200 == res.getStatusLine().getStatusCode()) { res.getEntity().writeTo(baos); return baos.toByteArray(); } else { throw new IOException("httpStatusCode:" + res.getStatusLine().getStatusCode()); } } finally { client.getConnectionManager().shutdown(); } } /** * 读取图片路径信息 * * @return */ @SuppressWarnings("unchecked") private void loadImagePathInfo() { long start = System.currentTimeMillis(); File file = new File(context.getCacheDir() + "/imagePathCache.json"); try { if (!file.isFile()) { // 文件不存在。 Log.d(TAG, "path info file does not exist"); imageGc(); return; } StringWriter sw = new StringWriter(); char[] buf = new char[1024]; int len; FileReader fr = new FileReader(file); while (-1 != (len = fr.read(buf))) { sw.write(buf, 0, len); } fr.close(); JSONObject json = new JSONObject(sw.toString()); Iterator<String> it = json.keys(); while (it.hasNext()) { String key = it.next(); int id = json.getInt(key); PathInfo pi = new PathInfo(); pi.url = key; pi.id = id; if (index < id) { index = id; } original.add(pi); } // 打开文件文件缓存成功 Log.i(TAG, "load path info ok."); } catch (IOException e) { Log.i(TAG, "load path info lost - IOException.", e); imageGc(); } catch (JSONException e) { Log.i(TAG, "load path info lost - JSONException.", e); imageGc(); } finally { if (file.exists()) { file.delete(); Log.d(TAG, "delete path info file"); } Log.d(TAG, "load path info time {" + (System.currentTimeMillis() - start) + "}"); } } /** * 如果路径信息加载失败,清理图片目录。 */ private void imageGc() { long start = System.currentTimeMillis(); try { File dir; if (sdCardExist) { dir = new File(Environment.getExternalStorageDirectory() + "/t_image/"); } else { dir = new File(context.getCacheDir() + "/t_image/"); } if (dir.isDirectory()) { for (File file : dir.listFiles()) { file.delete(); // gc Log.d(TAG_REF, "gc {" + file + "}"); } } } finally { // gc 计时 Log.d(TAG_REF, "gc time {" + (System.currentTimeMillis() - start) + "}"); } } private void newImagePathInfo(int max_size) { for (int i = original.size(); i < max_size; i++) { PathInfo pc = new PathInfo(); pc.id = index++; original.add(pc); } } /** * 保存图片路径信息(如记录,下次程序打开,可读取该记录已存图片继续可用) */ public void saveImagePathInfo() { long start = System.currentTimeMillis(); try { JSONObject json = new JSONObject(); for (PathInfo pi : use) { try { json.put(pi.url, pi.id); } catch (JSONException e) { e.printStackTrace(); } } File file = new File(context.getCacheDir() + "/imagePathCache.json"); try { FileWriter fw = new FileWriter(file); fw.write(json.toString()); fw.close(); Log.i(TAG, "image file info save ok."); } catch (IOException e) { e.printStackTrace(); Log.i(TAG, "image file info save lost."); file.delete(); } } finally { Log.d(TAG, "save time {" + (System.currentTimeMillis() - start) + "}"); } } /** * 图片加载回调 * * @author n.zhang * */ public static interface ILCallback { public void seed(Uri uri); } private class ImageViewCallback implements ILCallback { public ImageViewCallback(ImageView iv) { if (defaultImageID > 0) { iv.setImageResource(defaultImageID); } this.iv = iv; } private ImageView iv; public void seed(Uri uri) { File f = new File(uri.getPath()); iv.setImageURI(Uri.parse(f.toString())); f = null; } } // private class ImageButtonCallbacks implements ILCallback { // public ImageButtonCallbacks(ImageButton iv) { // if (defaultImageID > 0) { // iv.setBackgroundResource(defaultImageID); ////iv.setImageResource(defaultImageID); // } // this.iv = iv; // } // // private ImageButton iv; // // public void seed(Uri uri) { // iv.setImageURI(uri); // } // } // private class ButtonCallbacks implements ILCallback { // public ButtonCallbacks(Button iv) { // if (defaultImageID > 0) { // iv.setBackgroundResource(defaultImageID); ////iv.setImageResource(defaultImageID); // } // this.iv = iv; // } // // private Button iv; // // public void seed(Uri uri) { // iv.setImageURI(uri); // } // } private class ImageSwitcherCallbacks implements ILCallback { public ImageSwitcherCallbacks(ImageSwitcher iv) { if (defaultImageID > 0) { iv.setImageResource(defaultImageID); } this.iv = iv; } private ImageSwitcher iv; public void seed(Uri uri) { iv.setImageURI(uri); } }}