ImageLoader

来源:互联网 发布:sql select as table 编辑:程序博客网 时间:2024/06/06 15:44

ImageLoader

代码来源于android艺术开发探索 12章,主要为了减少加载图片的资源损耗,利用了下面2个知识点
1 LruCache and DiskLruCache两个缓冲
其中LruCache相当于一级缓存 , DiskLruCache相当于二级缓存,从LruCache中读取图片的速度最快,接下来是 DiskLruCache ,最慢就是从web服务器获取 , 所以在第一次我们会把数据网上下载下来后缓存到Disk和Memory中,下次的读取速度就会很快,注意的是在主线上可以进行LruCache操作,但是不建议这样进行 , DiskLruCache操作只能在后台线程执行
2 bitmap sacle缩放减少内存消耗
下面分析代码

博主git源代码: https://git.oschina.net/qianlilo/ImageLoader_util.git

Bitmap缩放

    #为什么要缩放哪? android给每个应用程序的内存是固定的 ,64M ,内存是宝贵的资源,    # 但是,一张图片长和宽都扩大到2倍,内存要扩大到4倍,但是由于人眼的限制或者显示器的限制,增加分辨率效果并不明显,所以我们要使用合适的分辨率    /**     * get bitmap from resourceId     * @param resId  resource Id     * @param reqWidth  require width     * @param reqHeight  require height     * */    public Bitmap decodeSampleBitmapFromResource(Resources res,                                                 int resId , int reqWidth , int reqHeight){        final BitmapFactory.Options options = new BitmapFactory.Options();        //only get pic size , in this do not consume real data        options.inJustDecodeBounds = true;        BitmapFactory.decodeResource(res , resId , options);        options.inSampleSize = calculateInSampleSize(options , reqWidth , reqHeight);        //can get real data from pic        options.inJustDecodeBounds = false;        return BitmapFactory.decodeResource(res , resId , options);    }     /**     * calculate shrink resolution     * @return more than 1     * @param options  pic info     * @param reqHeight require height     * @param reqWidth  require width     * */    private int calculateInSampleSize(BitmapFactory.Options options,                                      int reqWidth, int reqHeight) {        //judge argment        if(reqHeight == 0 || reqWidth == 0){            return  1;        }        final int height = options.outHeight;        final int width = options.outWidth;        Log.d(TAG, "origin pic { w = " +width + ", h = "+height+" } ");        int inSampleSize = 1;        if (height > reqHeight || width > reqWidth) {            final int halfHeight = height / 2;            final int halfWidth = width / 2;            while ( (halfHeight/inSampleSize) >= reqHeight                    && (halfWidth/inSampleSize) >= reqWidth) {                inSampleSize *= 2;            }        }        return inSampleSize;    }

线程池的使用

    #在这里使用线程池是因为每个图片都会去执行一个一次,开启多线程可以减少重复开启线程的资源开销     private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;    private static final int MAXNUM_POOL_SIZE = CPU_COUNT * 2 + 1;    private static final long KEEP_ALIVE = 10L;    private static final ThreadFactory sThreadFacory = new ThreadFactory() {        private final AtomicInteger mCount = new AtomicInteger(1);        @Override        public Thread newThread(@NonNull Runnable r) {            return new Thread(r , "ImageLoader#"+mCount.getAndIncrement());        }    };    public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(            CORE_POOL_SIZE , MAXNUM_POOL_SIZE , KEEP_ALIVE , TimeUnit.SECONDS ,            new LinkedBlockingQueue<Runnable>() , sThreadFacory);

LruChache的使用

    #由于lrucache是官方的,我们可以直接使用    #我们选取一个应用程序最大可以内存的1/8位缓存        int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024);        int cacheSize = maxMemory/8;        LruCache mMemoryCache = new LruCache<String, Bitmap>(cacheSize){            @Override            #计算每张图片的大小 , 根据代码是这个意思            protected int sizeOf(String key, Bitmap bitmap) {                return bitmap.getRowBytes() * bitmap.getHeight() / 1024;            }        };    /**     * add bitmap to memory cache 缓存到内存     * */    private void addBitmapToMemoryCache(String key,Bitmap bitmap){        if (getBitmapFromMemCache(key) == null) {            mMemoryCache.put(key , bitmap);        }    }    /**     *  get bitmap from memory cache 从内存得到缓存     * */    private Bitmap getBitmapFromMemCache(String key){        return mMemoryCache.get(key);    }    #可以发现不管是存还是取都很简单 , 书的作者这里使用了URl通过MD5得到key    #个人观点觉得在这里是有信息熵没什么必要,本来的URL就是明文,关于加密简单使用可以看我的另一个博客     # [这里写链接内容](http://blog.csdn.net/chenqianleo/article/details/76736575%20java%20%E4%BF%A1%E6%81%AF%E7%86%B5%20%E5%8A%A0%E5%AF%86)    private String hashKeyFromUrl(String url){        String cacheKey;        try {            final MessageDigest mDigest = MessageDigest.getInstance("MD5");            mDigest.update(url.getBytes());            cacheKey = bytesToHexString(mDigest.digest());        } catch (NoSuchAlgorithmException e) {            cacheKey = String.valueOf(url.hashCode());            e.printStackTrace();        }        return cacheKey;    }     private String bytesToHexString(byte[] bytes){        StringBuilder sb = new StringBuilder();        int len = bytes.length;        for (int i=0;i<len;i++){            String hex = Integer.toHexString(0xFF & bytes[i]);            if(hex.length() == 1){                sb.append('0');            }            sb.append(hex);        }        return sb.toString();    }

DiskLruCache

    #不是官方的,但是官方推荐这样使用,所以我们要直接拷贝一个DiskLruCache.java文件到项目,具体的可以上网或者下载源码来得到     DiskLruCache mDiskLruCache = DiskLruCache.open(diskCacheDir , 1 , 1 , DISKC_CACHE_SIZE);     #存 ,这里是先通过网络下载在缓存得到diskcache     private Bitmap loadBitmapFromHttp(String uri, int reqWidth, int reqHeight) throws IOException {       #在UI线程不可以使用网络耗时操作        if(Looper.myLooper() == Looper.getMainLooper()){            throw new RuntimeException("can not visit netWork from UI thread");        }        if(mDiskLruCache == null){            return null;        }        String key = hashKeyFromUrl(uri);        #开始存        DiskLruCache.Editor editor = mDiskLruCache.edit(key);        if (editor != null) {            OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX);            //这个函数是把url的内容存到outputstream中去            if (downloadUrlToStream(uri, outputStream)) {                editor.commit();            } else {                editor.abort();            }            mDiskLruCache.flush();        }        return loadBitmapFromDiskCache(uri , reqWidth , reqHeight);    }     #取    private Bitmap loadBitmapFromDiskCache(String uri, int reqWidth, int reqHeight)            throws IOException {        if(Looper.myLooper() == Looper.getMainLooper()){            Log.e(TAG, " load bitmap from UI thread, not recommended" );        }        if(mDiskLruCache == null){            return null;        }        Bitmap bitmap = null;        String key = hashKeyFromUrl(uri);        DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);        if(snapshot != null){            FileInputStream fileInputStream = (FileInputStream) snapshot.getInputStream(DISK_CACHE_INDEX);            FileDescriptor fileDescriptor = fileInputStream.getFD();            #自己实现的,使用了上面介绍的缩放            bitmap = mImageResizer.decodeSampleBitmapFromFileDescriptor(fileDescriptor ,                    reqWidth , reqHeight);            # 内存缓存中没有 , 缓存到内存中去                    if(bitmap != null){                addBitmapToMemoryCache(key , bitmap);            }        }        return bitmap;    }

完整的代码实现了照片墙的功能,可以下载代码看完整demo

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 乌鲁木齐信息采集结束后怎么办 头发很长时间不长怎么办啊 打嘟噜时间不长怎么办 阴茎勃起的时间不长怎么办 睡觉的时间不长怎么办 每次锻炼时间不长怎么办 微信好友不知道是谁怎么办 就一个软件闪退怎么办 葫芦侠修改闪退怎么办 戴尔游匣磁盘占用100怎么办 步步高家教机扫描笔不亮怎么办 社保卡手机号换了怎么办 香港公司进出口没有申报怎么办 智能电视右上角网络未连接怎么办 电子秤按键板不好用怎么办失灵 桑塔纳车钥匙锁车里了怎么办 舌头上有锯齿印怎么办 夏天有脚气脚臭怎么办 xp分辨率太高黑屏怎么办 农村淘宝标识类目没了怎么办 被投诉到食品监督局怎么办 被客户315投诉了怎么办 给人打不接受调解怎么办 失业证年审忘了怎么办 工商年检过期4天怎么办 个体营业执照年审过期了怎么办 企业年报密码忘了怎么办 税务年报报错了怎么办 工商证过期5年怎么办 车年检标志丢了怎么办 年检标志打错了怎么办 贵州个体出租车工商执照年检怎么办 驾驶证考试预约提示网络繁忙怎么办 帝豪显示屏花屏怎么办 注册公司居委会不盖章怎么办 营业执照名字和店名不一样怎么办 开炸鸡店没经验怎么办 提名候选人时重名重姓怎么办 别人用我的店名怎么办 wish店铺出现侵权产品怎么办 如果公司缺人该怎么办