返回顶部

收藏

Android图片加载的缓存类

更多
    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 &amp;&amp; !bmp.isRecycled()) {  
                LogHelper.e("ImageLoaderEngine","一级缓存获取:"+id);  
                return bmp;  
            }  
            // 2. 从二级缓存中获取  
            bmp = getFromSecondLevelCache(id);  
            if (bmp != null &amp;&amp; !bmp.isRecycled()) {  
                LogHelper.e("ImageLoaderEngine","二级缓存获取:"+id);  
                return bmp;  
            }  

            if(bmp != null &amp;&amp; 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 &amp;&amp; !bmp.isRecycled()) {  
                LogHelper.e("ImageLoaderEngine","一级缓存获取:"+id);  
                return bmp;  
            }  
            // 2. 从二级缓存中获取  
            bmp = getFromSecondLevelCache(id);  
            if (bmp != null &amp;&amp; !bmp.isRecycled()) {  
                LogHelper.e("ImageLoaderEngine","二级缓存获取:"+id);  
                return bmp;  
            }  
            // 3. 从SD卡缓存中获取  
            bmp = getFromSDCache(moment, photoTag);  
            if (bmp != null &amp;&amp; !bmp.isRecycled()) {  
                LogHelper.e("ImageLoaderEngine","SD卡缓存获取:"+id);  
                return bmp;  
            }  
            // 4. 从网络中获取  
            loadImageByMoment(moment, photoTag);   
    //        LogHelper.e("ImageLoaderEngine","本地获取图片失败:"+moment.id+"="+moment.getPicture());  

            if(bmp != null &amp;&amp; bmp.isRecycled()) {  
                return null;  
            } else {  
                return bmp;  
            }  
        }  

        public Bitmap getImage(String key,String url) {  
            Bitmap bmp = null;  
            // 1. 从一级缓存中获取  
            bmp = getFromFirstLevelCache(key);  
            if (bmp != null &amp;&amp; !bmp.isRecycled()) {  
                return bmp;  
            }  
            // 2. 从二级缓存中获取  
            bmp = getFromSecondLevelCache(key);  
            if (bmp != null &amp;&amp; !bmp.isRecycled()) {  
                return bmp;  
            }  
            // 3. 从SD卡缓存中获取  
            bmp = getFromSDCacheByKey(key,0);  
            if (bmp != null &amp;&amp; !bmp.isRecycled()) {  
                return bmp;  
            }  
            // 4. 从网络中获取  
            loadImageByUrl(key, url,0);  

            if(bmp != null &amp;&amp; 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() &amp;&amp; !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() &amp;&amp; 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() &amp;&amp; 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;  
        }  
    }  

来自:http://blog.csdn.net/h3c4lenovo/article/details/27060505

标签:java

收藏

0人收藏

支持

0

反对

0

发表评论