zoukankan      html  css  js  c++  java
  • 异步图片加载、内存、磁盘缓存

    该类实现的功能:

    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

    功能很完善、很强大了








  • 相关阅读:
    查找文献的BibTex
    123. 单词搜索(DFS)
    423 Locked
    Win7 ODBC驱动 Excel (转)
    存储过程如何传变量到like下
    表的倒数第二行数据
    oracle跟踪
    PL/SQL-FOR UPDATE 与 FOR UPDATE OF的区别
    oracle for loop
    sqlserver中sp_executesql使用实例(获取动态sql输出结果)
  • 原文地址:https://www.cnblogs.com/zhouzme/p/5758458.html
Copyright © 2011-2022 走看看