异步图片加载、内存、磁盘缓存

来源:互联网 发布:淘宝卖自产自销农产品 编辑:程序博客网 时间:2024/06/05 06:16

该类实现的功能:

1. 异步加载远程图片

2. 图片内存缓存

3. 异步图片磁盘缓存


package com.ai9475.util;import android.graphics.Bitmap;import android.graphics.drawable.BitmapDrawable;import android.graphics.drawable.Drawable;import android.os.Handler;import android.os.Message;import com.ai9475.meitian.AppConfig;import com.ai9475.meitian.AppException;import com.ai9475.meitian.AppManager;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.lang.ref.SoftReference;import java.net.HttpURLConnection;import java.net.URL;import java.util.Date;import java.util.HashMap;/** * 图片加载管理器 * * Created by ZHOUZ on 14-2-7. */public final class ZImageLoader{    private static final String TAG = "ZImageLoader";    private static final ZImageLoader INSTANCE = new ZImageLoader();    private static String mCacheBasePath = null;    private boolean mUseDiskCache = false;    private int mExpireTime = 86400;    private String mCacheSubDir = "common";    private HashMap<String, SoftReference<Drawable>> mImageCache = new HashMap<String, SoftReference<Drawable>>();    public static ZImageLoader getInstance() {        return INSTANCE;    }    /**     * 设置 SD 卡中的图片缓存有效时长(单位:秒)     *     * @param time     */    public void setExpireTime(int time) {        this.mExpireTime = time;    }    /**     * 设置是否使用存储卡缓存图片     *     * @param isUse     */    public void setUseDiskCache(Boolean isUse) {        this.mUseDiskCache = isUse;    }    /**     * 设置缓存根目录     *     * @param path     */    public static void setCacheBasePath(String path) {        mCacheBasePath = path;    }    /**     * 设置缓存根目录下的子目录     *     * @param dir     */    public void setmCacheSubDir(String dir) {        this.mCacheSubDir = dir;    }    /**     * 加载图片的多线程控制     *     * @param imageUrl     * @param tag     * @param listener     */    public void loadDrawable(final String imageUrl, final String tag, final OnImageLoadListener listener)    {        // 异步多线程加载图片后的数据传递处理        final Handler handler = new Handler() {            @Override            public void handleMessage(Message message) {                if (message.what == 1) {                    listener.onSuccess((Drawable) message.obj, imageUrl, tag);                } else {                    listener.onFailure((IOException) message.obj, imageUrl, tag);                }            }        };        // 通过线程池来控制管理图片加载        AppManager.getFixedExecutorsService().submit(new Runnable() {            @Override            public void run() {                Message msg;                try {                    Drawable drawable = null;                    // 是否已缓存过图片, 是则从缓存中直接获取, 若缓存中数据丢失则重新远程加载                    if (mImageCache.containsKey(imageUrl)) {                        SoftReference<Drawable> softReference = mImageCache.get(imageUrl);                        if (softReference != null) {                            Drawable d = softReference.get();                            if (d != null) {                                ZLog.i(TAG, "load image from memory cache");                                drawable = d;                            }                        }                    }                    if (drawable == null) {                        drawable = loadImageFromUrl(imageUrl);                        if (drawable != null) {                            mImageCache.remove(imageUrl);                            mImageCache.put(imageUrl, new SoftReference<Drawable>(drawable));                        }                    }                    msg = handler.obtainMessage(1, drawable);                } catch (IOException e) {                    msg = handler.obtainMessage(0, e);                }                handler.sendMessage(msg);            }        });    }    /**     * 加载远程图片或本地图片缓存文件     *     * @param imageUrl     * @return     * @throws java.io.IOException     */    public Drawable loadImageFromUrl(String imageUrl) throws IOException    {        // 检查 SD 卡是否可用并将图片缓存到 SD 卡上        if (mUseDiskCache && mCacheBasePath != null)        {            File d = new File(mCacheBasePath + mCacheSubDir);            if (! d.exists()) {                d.mkdirs();            }            final File f = new File(d.getPath() + File.separator + ZHelper.md5(imageUrl));            long time = (new Date()).getTime();            long expire = time - (mExpireTime * 1000L);            // 文件存在且在有效期内则直接读取            if (f.exists() && f.lastModified() > expire) {                ZLog.i(TAG, "load image file disk cache");                FileInputStream fis = new FileInputStream(f);                return Drawable.createFromStream(fis, "src");            }            // 远程加载图片后写入到 SD 卡上            InputStream i = this.getImageInputStream(imageUrl);            if (i == null) {                return null;            }            final Drawable drawable = Drawable.createFromStream(i, "src");            if (drawable == null) {                return null;            }            // 将图片异步写入到本地 SD 卡中缓存, 避免阻塞UI线程, 导致图片不能显示            new Thread(new Runnable() {                @Override                public void run() {                    ZLog.i(TAG, "async write image file disk cache");                    try {                        BitmapDrawable bd = (BitmapDrawable) drawable;                        Bitmap bitmap = bd.getBitmap();                        FileOutputStream out = new FileOutputStream(f);                        bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);                        out.close();                    } catch (IOException e) {                        ZLog.e(TAG, "write image cache IOException: "+ e.getMessage());                        AppException.io(e);                    }                }            }).start();            return drawable;        }        // 只读取远程图片不缓存        else {            InputStream i = this.getImageInputStream(imageUrl);            if (i == null) {                return null;            }            return Drawable.createFromStream(i, "src");        }    }    /**     * 远程加载图片数据     *     * @param imageUrl     * @return     * @throws java.io.IOException     */    public InputStream getImageInputStream(String imageUrl) throws IOException    {        ZLog.i(TAG, "load image from url");        if (! ZConnectivity.isNetworkConnected()) {            ZLog.i(TAG, "net work not connected");            return null;        }        URL m = new URL(imageUrl);        HttpURLConnection conn = (HttpURLConnection) m.openConnection();        conn.setRequestMethod("GET");        conn.setUseCaches(false);        conn.setDoInput(true);        conn.setConnectTimeout(5000);        conn.setReadTimeout(30000);        conn.setInstanceFollowRedirects(true);        return conn.getInputStream();    }    /**     * 加载图片的事件监听器     */    public interface OnImageLoadListener {        /**         * 图片加载完成事件处理         *         * @param imageDrawable         * @param imageUrl         * @param tag         */        public void onSuccess(Drawable imageDrawable, String imageUrl, String tag);        /**         * 图片加载失败的事件处理         *         * @param e         * @param imageUrl         * @param tag         */        public void onFailure(IOException e, String imageUrl, String tag);    }}


使用方法:

    /**     * 日记照片加载事件监听     */    private class OnPicLoadListener extends OnImageLoadListener    {        private int mImageSource = R.drawable.default_pic;        /**         * 设置图片         *         * @param view         * @param imageUrl         * @param tag         * @param drawable         */        public void setDrawable(ImageView view, String imageUrl, String tag, Drawable drawable)        {            if (view == null) return;            int height = 0;            if (mImagesHeight.containsKey(imageUrl)) {                height = mImagesHeight.get(imageUrl);            }            View ct = ((View) view.getParent()).findViewById(R.id.calendarCt);            if (ct != null) {                ct.setVisibility(View.INVISIBLE);            }            if (drawable != null) {                // 定义图片的最佳高度                if (height == 0) {                    int minHeight = ZUI.dp2px(mContext, PIC_MIN_HEIGHT);                    int maxHeight = ZUI.dp2px(mContext, PIC_MAX_HEIGHT);                    height = (int) ((float) view.getWidth() / drawable.getMinimumWidth() * drawable.getMinimumHeight());                    if (height > maxHeight) {                        height = maxHeight;                    } else if (height < minHeight) {                        height = minHeight;                    }                    mImagesHeight.put(imageUrl, height);                }                // 现将图片完全透明                drawable.setAlpha(0);                view.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, height));                view.setScaleType(ImageView.ScaleType.CENTER_CROP);                view.setImageDrawable(drawable);                // 添加透明渐变动画显示图片                AlphaAnimation alphaAnim = new AlphaAnimation(0.0f, 1.0f);                alphaAnim.setDuration(100);                view.setAnimation(alphaAnim);                if (ct != null) {                    ct.setVisibility(View.VISIBLE);                }            } else {                int minHeight = ZUI.dp2px(mContext, PIC_MIN_HEIGHT);                height = height < minHeight ? minHeight : height;                view.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, height));                view.setScaleType(ImageView.ScaleType.CENTER);                view.setImageResource(mImageSource);            }        }    }    /**     * 图片的加载监听事件     */    abstract private class OnImageLoadListener implements ZImageLoader.OnImageLoadListener    {        /**         * 实现图片显示的抽象方法         *         * @param view         * @param tag         * @param drawable         */        abstract public void setDrawable(ImageView view, String imageUrl, String tag, Drawable drawable);        @Override        public void onSuccess(Drawable drawable, String imageUrl, String tag) {            ImageView view = (ImageView) mDiaryListView.findViewWithTag(tag == null ? imageUrl : tag);            this.setDrawable(view, imageUrl, tag, drawable);        }        @Override        public void onFailure(IOException e, String imageUrl, String tag) {            //Toast.makeText(mContext, e.toString(), Toast.LENGTH_SHORT).show();        }    }// 调用该方法ZImageLoader.getInstance().loadDrawable(item.getPicUrl(), item.getPicTag(), this.mOnPicLoadListener);


这是之前自己实现的简单的图片加载缓存类,不过今天开始尝试使用开源的《Android Universal Image Loader》,先把代码贴在这儿也算做个备份吧

github项目地址:https://github.com/nostra13/Android-Universal-Image-Loader

功能很完善、很强大了








0 0