图片加载的缓存类

来源:互联网 发布:小米网络电视 编辑:程序博客网 时间:2024/05/24 01:49

代码是自己写的,用在公司项目上。后来因为某些原因弃用了,所以我把它开源出来。代码并没有什么讲解和注释,主要为了自己以后方便查看。

import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;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.LinkedHashMap;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Build;import android.os.Handler;import android.text.TextUtils;/** * 图片加载器,主要功能是从网络中下载图片并缓存。这里之所以另写一个功能类似重复的原因是 之前旧的图片加载逻辑感觉非常复杂,我这里写个轻量级的 *  * @author H3c *  */public class ImageLoaderEngine {    public static final int LOAD_IMG_SUCCESS = 2010;    private final int MAX_CAPACITY = Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1 ? 50 : 10;// 一级缓存缓存图片数    private static ImageLoaderEngine instance;    private static Handler mHandler;    private ExecutorService pool;// 后台线程池    // 这里用LinkedHashMap不用LruCache的原因是LruCache直接申请内存大小而不是图片个数。此App已经有一个全局的LruCache了,重复申请内存大小对应用不利    private LinkedHashMap<String, Bitmap> mFirstLevelCache;// <momentId>一级缓存,硬链接bitmap,只保留最近用的图片。    private ConcurrentHashMap<String, SoftReference<Bitmap>> mSecondLevelCache;// <momentId>    public static ImageLoaderEngine getInstance(Handler handler) {        if (instance == null) {            instance = new ImageLoaderEngine();        }        if(handler != null) {            mHandler = handler;        }        return instance;    }    private ImageLoaderEngine() {        pool = Executors.newFixedThreadPool(4);// 默认线程池大小为6        initCache();    }    private void initCache() {        mFirstLevelCache = new LinkedHashMap<String, Bitmap>(MAX_CAPACITY / 2,                0.75f, true) {            private static final long serialVersionUID = 1L;            protected boolean removeEldestEntry(Entry<String, Bitmap> eldest) {                if (size() > MAX_CAPACITY) {// 超过一级缓存大小后会挪到二级缓存中                    mSecondLevelCache.put(eldest.getKey(),                            new SoftReference<Bitmap>(eldest.getValue()));                    return true;                }                return false;            };        };        mSecondLevelCache = new ConcurrentHashMap<String, SoftReference<Bitmap>>();// <momentId>    }        /**     * 移除缓存     * @param key     */    public void deleteCacheByKey(String key) {        String sdCacheingPath = IOHelper.getCachedPicturePath(                Global.packageName, key);        String sdCacheedPath = sdCacheingPath +".png";        File file = new File(sdCacheingPath);        if(file.exists()) {            file.delete();        }        file = new File(sdCacheedPath);        if(file.exists()) {            file.delete();        }                mFirstLevelCache.remove(key);        mSecondLevelCache.remove(key);    }    /**     * 释放资源     */    public void recycleImageLoader() {        new Thread(new Runnable() {            @Override            public void run() {                if (pool != null) {                    pool.shutdownNow();                }                if (mFirstLevelCache != null) {                    for (Bitmap bmp : mFirstLevelCache.values()) {                        if (bmp != null) {                            bmp.recycle();                            bmp = null;                        }                    }                    mFirstLevelCache.clear();                    mFirstLevelCache = null;                }                if (mSecondLevelCache != null) {                    mSecondLevelCache.clear();                }                mHandler = null;            }        }).start();    }    /**     * 后台请求图片     *      * @param item     */    public void loadImageByMoment(final NMoment moment,String photoTag) {        if (moment.isPicture()                || moment.isVideo()) {            String id = moment.id + photoTag;            loadImageByUrl(id+"", moment.getPicture(Global.widthPixels/3*2),moment.orientation);        }    }        /**     * 后台请求图片     * @param key     * @param url     */    public void loadImageByUrl(final String key,final String url,final int orientation) {            pool.submit(new Runnable() {                public void run() {                    LogHelper.e("ImageLoaderEngine","从网络中下载");                    // 如果内存中有就算了                    if (mFirstLevelCache.get(key) != null                            || mSecondLevelCache.get(key) != null) {// 如果图片已经缓存了                        LogHelper.e("ImageLoaderEngine","下载图片错误 1");                        return;                    }                    // 如果SD卡缓存中有就算了                    final String sdCacheingPath = IOHelper.getCachedPicturePath(                            Global.packageName, key);                    File cacheingFile = new File(sdCacheingPath);                    if (cacheingFile.exists()) {// 如果正在缓存就算了                        long currentTime = System.currentTimeMillis();                        if((currentTime - cacheingFile.lastModified()) >2 * 60 * 1000) {                            LogHelper.e("ImageLoaderEngine","2分钟都还没下载完,准备删除它.."+currentTime+"="+cacheingFile.lastModified());                            cacheingFile.delete();                        } else {                            getBitmapFromNetworkAndAddToMemory(url, key, orientation);                            LogHelper.e("ImageLoaderEngine","第二次进来应该走这里..");                            return;                        }                    }                                        String sdCacheedPath = sdCacheingPath + ".png";// 缓存完成后会改名字,否则会导致缓存错误,图片变黑                    File cacheedFile = new File(sdCacheedPath);                    if (cacheedFile.exists()) {// 如果缓存了就算了                        LogHelper.e("ImageLoaderEngine","下载图片错误 2");                        return;                    }                                        getBitmapFromNetworkAndAddToMemory(url, key, orientation);                }            });    }        private void getBitmapFromNetworkAndAddToMemory(String url,String key,int orientation) {        Bitmap bmp = getBitmapFromUrl(url);        if(bmp!= null) {            LogHelper.e("ImageLoaderEngine","下载网络图片成功");                        if(key.endsWith("_DetailDaily")) {                bmp = scaledBitmap(bmp, Global.getThumbWidth());            }                        if(orientation != 0) {                mFirstLevelCache.put(key, ViewHelper.rotateBitmap(orientation, bmp));// 从网络下载后直接显示            } else {                mFirstLevelCache.put(key, bmp);// 从网络下载后直接显示            }                    if (mHandler != null) {                mHandler.removeMessages(LOAD_IMG_SUCCESS);                mHandler.sendEmptyMessageDelayed(                        LOAD_IMG_SUCCESS, 600);// 延时提示没有数据了            }                        final String sdCacheingPath = IOHelper.getCachedPicturePath(                    Global.packageName, key);            saveBitmapToFile(sdCacheingPath, bmp);        } else {            LogHelper.e("ImageLoaderEngine","下载网络图片失败...");        }    }        /**     * 直接从网络中获取     * @param url     * @return     */    public Bitmap getBitmapFromUrl(String url) {        URL myFileUrl = null;        Bitmap bitmap = null;        InputStream is = null;        try {        if (!UIUtils.isNetworkAvailable(MyApplication.getInstance())) {        return null;        }            myFileUrl = new URL(url);            HttpURLConnection conn = (HttpURLConnection) myFileUrl                    .openConnection();            conn.setDoInput(true);            conn.connect();            is = conn.getInputStream();            bitmap = BitmapFactory.decodeStream(is);        } catch (Exception e) {            try {                if(is != null) {                    is.close();                }            } catch (IOException e1) {                e1.printStackTrace();            }            e.printStackTrace();        }        return bitmap;    }        public Bitmap getImageInMemory(NMoment moment) {        return getImageInMemory(moment, "");    }        /**     * 新增接口,可以根据tag重新标识Moment,这样可以扩展应用场景,比如首页需要大图,进入相集页需要小图     * @param moment     * @param photoTag     * @return     */    public Bitmap getImageInMemory(NMoment moment, String photoTag) {        String id = moment.id + photoTag;                Bitmap bmp = null;        // 1. 从一级缓存中获取        bmp = getFromFirstLevelCache(id);        if (bmp != null && !bmp.isRecycled()) {            LogHelper.e("ImageLoaderEngine","一级缓存获取:"+id);            return bmp;        }        // 2. 从二级缓存中获取        bmp = getFromSecondLevelCache(id);        if (bmp != null && !bmp.isRecycled()) {            LogHelper.e("ImageLoaderEngine","二级缓存获取:"+id);            return bmp;        }                if(bmp != null && bmp.isRecycled()) {            return null;        } else {            return bmp;        }    }        public void setImage(String key,Bitmap picture) {        mFirstLevelCache.put(key, picture);    }        /**     * 获取图片     */    public Bitmap getImage(NMoment moment) {        return getImage(moment, "");    }        public Bitmap getImage(NMoment moment, String photoTag) {        String id = moment.id + photoTag;        Bitmap bmp = null;        // 1. 从一级缓存中获取        bmp = getFromFirstLevelCache(id);        if (bmp != null && !bmp.isRecycled()) {            LogHelper.e("ImageLoaderEngine","一级缓存获取:"+id);            return bmp;        }        // 2. 从二级缓存中获取        bmp = getFromSecondLevelCache(id);        if (bmp != null && !bmp.isRecycled()) {            LogHelper.e("ImageLoaderEngine","二级缓存获取:"+id);            return bmp;        }        // 3. 从SD卡缓存中获取        bmp = getFromSDCache(moment, photoTag);        if (bmp != null && !bmp.isRecycled()) {            LogHelper.e("ImageLoaderEngine","SD卡缓存获取:"+id);            return bmp;        }        // 4. 从网络中获取        loadImageByMoment(moment, photoTag); //        LogHelper.e("ImageLoaderEngine","本地获取图片失败:"+moment.id+"="+moment.getPicture());                if(bmp != null && bmp.isRecycled()) {            return null;        } else {            return bmp;        }    }    public Bitmap getImage(String key,String url) {        Bitmap bmp = null;        // 1. 从一级缓存中获取        bmp = getFromFirstLevelCache(key);        if (bmp != null && !bmp.isRecycled()) {            return bmp;        }        // 2. 从二级缓存中获取        bmp = getFromSecondLevelCache(key);        if (bmp != null && !bmp.isRecycled()) {            return bmp;        }        // 3. 从SD卡缓存中获取        bmp = getFromSDCacheByKey(key,0);        if (bmp != null && !bmp.isRecycled()) {            return bmp;        }        // 4. 从网络中获取        loadImageByUrl(key, url,0);                if(bmp != null && bmp.isRecycled()) {            return null;        } else {            return bmp;        }    }        /**     * 一级缓存获取图片     *      * @param imgId     * @return     */    private Bitmap getFromFirstLevelCache(String imgId) {        Bitmap bitmap = null;        synchronized (mFirstLevelCache) {            bitmap = mFirstLevelCache.get(imgId);            if (bitmap != null) {                mFirstLevelCache.remove(imgId);                mFirstLevelCache.put(imgId, bitmap);            }        }        return bitmap;    }    /**     * 二级缓存获取图片     *      * @param url     * @return     */    private Bitmap getFromSecondLevelCache(String imgId) {        Bitmap bitmap = null;        SoftReference<Bitmap> softReference = mSecondLevelCache.get(imgId);        if (softReference != null) {            bitmap = softReference.get();            if (bitmap == null) {                mSecondLevelCache.remove(imgId);            }        }        return bitmap;    }    /**     * 从SD卡缓存获取图片,并放入一级缓存中     *      * @param moment     * @return     * @throws IOException     */    private Bitmap getFromSDCache(final NMoment moment,final String photoTag) {        Bitmap drawable = null;        String id = moment.id + photoTag;                String sdCacheingPath = IOHelper.getCachedPicturePath(Global.packageName,                id);                String sdCacheedPath = sdCacheingPath + ".png";        if(moment.isLocal){            if(moment.isVideo()) {            //获取本地路径                sdCacheedPath = moment.getPicture(Global.widthPixels/3*2);            } else {                sdCacheedPath = moment.local_res_path;            }        }                File cacheFile = new File(sdCacheedPath);        if (!cacheFile.exists()) {// 如果没有缓存完成就退出            LogHelper.e("ImageLoaderEngine","找不到缓存文件:"+sdCacheedPath);            if(!TextUtils.isEmpty(moment.local_res_path)) {// 如果本地有图片,就先用本地图片代替                sdCacheedPath = moment.local_res_path;                cacheFile = new File(sdCacheedPath);                if (cacheFile.exists() && !GlobalData.PHONE_MANUFACTURER.equalsIgnoreCase("samsung")) {                    LogHelper.e("ImageLoaderEngine","AK47...:"+GlobalData.PHONE_MANUFACTURER);// 先从本地找替代图片..                    new Thread(new Runnable() {// 从网络下载                        @Override                        public void run() {                            loadImageByMoment(moment, photoTag);                         }                    }).start();                    return getFitPhoto(sdCacheedPath, moment, cacheFile);                } else {                    return null;                }            } else {                return null;            }        }                drawable = getFitPhoto(sdCacheedPath, moment, cacheFile);        if (drawable != null) {            if (moment.orientation != 0) {                drawable = ViewHelper                        .rotateBitmap(moment.orientation, drawable);            }            if(mFirstLevelCache != null) {                mFirstLevelCache.put(id, drawable);            }        } else {            cacheFile.delete();        }        return drawable;    }        private Bitmap getFitPhoto(String sdCacheedPath,NMoment moment,File cacheFile) {        FileInputStream fs = null;        Bitmap result;        try {            BitmapFactory.Options options = new BitmapFactory.Options();            options.inJustDecodeBounds = true;            BitmapFactory.decodeFile(sdCacheedPath, options);            int hRatio = (int) Math.ceil(options.outHeight                    / (float) moment.picture_height); // 算高度            int wRatio = (int) Math.ceil(options.outWidth                    / (float) Global.widthPixels); // 算宽度            if (hRatio > 1 || wRatio > 1) {                if (hRatio > wRatio) {                    options.inSampleSize = hRatio;                } else                    options.inSampleSize = wRatio;            }            options.inPurgeable = true;            options.inInputShareable = true;            options.inDither = false;            options.inJustDecodeBounds = false;            try {                fs = new FileInputStream(cacheFile);            } catch (FileNotFoundException e) {                e.printStackTrace();            }            result = BitmapFactory.decodeFileDescriptor(fs.getFD(), null,                    options);        } catch (Exception e) {            throw new RuntimeException(e);        } finally {            if (fs != null) {                try {                    fs.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }        return result;    }        private Bitmap getFromSDCacheByKey(String key,int orientation) {        Bitmap drawable = null;        FileInputStream fs = null;                String sdCacheedPath = IOHelper.getCachedPicturePath(                Global.packageName, key) + ".png";                File cacheFile = new File(sdCacheedPath);        if (!cacheFile.exists()) {// 如果没有缓存完成就退出            return null;        }        try {            BitmapFactory.Options options = new BitmapFactory.Options();            options.inJustDecodeBounds = true;            BitmapFactory.decodeFile(sdCacheedPath, options);            int wRatio = (int) Math.ceil(options.outWidth                    / (float) Global.widthPixels); // 算宽度            options.inSampleSize = wRatio;            options.inPurgeable = true;            options.inInputShareable = true;            options.inDither = false;            options.inJustDecodeBounds = false;            try {                fs = new FileInputStream(cacheFile);            } catch (FileNotFoundException e) {                e.printStackTrace();            }                        drawable = BitmapFactory.decodeFileDescriptor(fs.getFD(), null,                    options);            if (drawable != null) {                if(orientation != 0) {                    drawable = ViewHelper.rotateBitmap(orientation, drawable);                }                mFirstLevelCache.put(key, drawable);            } else {                cacheFile.delete();            }        } catch (Exception e) {            throw new RuntimeException(e);        } finally {            if (fs != null) {                try {                    fs.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }        return drawable;    }    /**     * 创建一个灰色的默认图     * @param moment     * @return     */    public Bitmap getDefaultBitmap(NMoment moment) {        return ImageHelper.createBitmap(moment.picture_width, moment.picture_height,                R.color.image_bg_daily);    }        /**     * 保存Bitmap文件到sd卡,传入jpg结尾的路径     * @param filePath     * @param mBitmap     */    public void saveBitmapToFile(String filePath, Bitmap mBitmap) {        try {            File file = new File(filePath);            if (!file.getParentFile().exists()) {                file.getParentFile().mkdirs();            }            if (file.exists() && file.length() > 0) {                long currentTime = System.currentTimeMillis();                if ((currentTime - file.lastModified()) > 2 * 60 * 1000) {                    LogHelper.e("ImageLoaderEngine",                            "2分钟都还没下载完,准备删除它.." + currentTime + "="                                    + file.lastModified());                    file.delete();                } else {                    return;                }            } else {                file.createNewFile();            }            FileOutputStream fOut = null;            fOut = new FileOutputStream(file);            mBitmap.compress(Bitmap.CompressFormat.JPEG, 80, fOut);            fOut.flush();            fOut.close();                        file.renameTo(new File(filePath+".png"));        } catch (Exception e) {            e.printStackTrace();            LogHelper.e("ImageLoaderEngine","保存图片错误:"+e);        }        LogHelper.e("ImageLoaderEngine","保存网络图片成功"+filePath+".png");    }    /**     * 保存文件至缓存,这里重写而不用IOHelper里面的原因是IOHelper里面过于复杂     *      * @param url     * @param filePath     * @return     */    public boolean saveUrlBitmapToFile(String url, String filePath) {    if (TextUtils.isEmpty(filePath)) {    return false;    }        File iconFile = new File(filePath);        if (iconFile.getParentFile() == null) {        return false;        }        if (!iconFile.getParentFile().exists()) {            iconFile.getParentFile().mkdirs();        }        if (iconFile.exists() && iconFile.length() > 0) {            long currentTime = System.currentTimeMillis();            if((currentTime - iconFile.lastModified()) >2 * 60 * 1000) {                LogHelper.e("ImageLoaderEngine","2分钟都还没下载完,准备删除它.."+currentTime+"="+iconFile.lastModified());                iconFile.delete();            } else {                return true;            }        }        FileOutputStream fos = null;        InputStream is = null;        try {            fos = new FileOutputStream(filePath);            is = new URL(url).openStream();            int data = is.read();            while (data != -1) {                fos.write(data);                data = is.read();            }        } catch (IOException e) {            LogHelper.e("ImageLoaderEngine", "ImageLoaderEngine 下载图片错误" + e);            iconFile.delete();            e.printStackTrace();            return false;        } finally {            try {                if (is != null) {                    is.close();                }                if (fos != null) {                    fos.close();                }            } catch (IOException e) {                e.printStackTrace();            }        }        iconFile.renameTo(new File(filePath+".png"));        return true;    }        /**     * 缩放bitmap     * @param bmp     * @param scaledValue缩放值     * @return     */    public Bitmap scaledBitmap(Bitmap bmp,int scaledValue) {        int bmpWidth = bmp.getWidth();        int bmpHeight = bmp.getHeight();                if(bmpWidth >= bmpHeight) {// 横图            bmpWidth = (bmpWidth *  scaledValue / bmpHeight);            bmpHeight = scaledValue;        } else {            bmpHeight = (bmpHeight *  scaledValue / bmpWidth);            bmpWidth = scaledValue;        }                Bitmap scaledBmp = Bitmap.createScaledBitmap(bmp,bmpWidth,bmpHeight,true);        bmp.recycle();        bmp = null;                return scaledBmp;    }}


1 0