(备忘)图片加载帮助类(自动异步加载、图片文件缓存、缓存文件管理)

来源:互联网 发布:医疗大数据平台 编辑:程序博客网 时间:2024/05/10 07:43
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);        }    }}
原创粉丝点击