美文网首页
Bitmap的加载和缓存

Bitmap的加载和缓存

作者: 要学的东西太多了 | 来源:发表于2018-10-12 17:48 被阅读0次

    1.BitmapFactory提供了四类方法来加载Bitmap:decodeByteArray、decodeFile、decodeResource、decodeStream。其中,decodeFile和decodeResource间接调用了decodeStream方法,最终都是调用BitmapFactory的native方法。getAllocationByteCount()方法可以获取bitmap的字节大小。

    2.Bitmap压缩一般采用下面思路:

    public class BitmapUtils {
        
        public static Bitmap decodeBitmapByResource(Resources res , int resId , int viewWidth , int viewHeight){
            return decodeBitmapByResource(null,resId,viewWidth,viewHeight);
        }
    
        public static Bitmap decodeBitmapByResource(BitmapCache cache,Resources res , int resId , int viewWidth , int viewHeight){
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeResource(res,resId,options);
            dealOptions(cache,options,viewWidth,viewHeight);
            Bitmap candidate = BitmapFactory.decodeResource(res,resId,options);
            if(cache!=null) {
                cache.setCandidate(candidate);
            }
            return candidate;
        }
    
        public static Bitmap decodeBitmapByFile( String filePath , int viewWidth , int viewHeight){
            return decodeBitmapByFile(null,filePath,viewWidth,viewHeight);
        }
    
        public static Bitmap decodeBitmapByFile(BitmapCache cache , String filePath , int viewWidth , int viewHeight){
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(filePath,options);
            dealOptions(cache,options,viewWidth,viewHeight);
            Bitmap candidate = BitmapFactory.decodeFile(filePath,options);
            if(cache!=null) {
                cache.setCandidate(candidate);
            }
            return candidate;
        }
    
        public static Bitmap decodeBitmapByBytes( byte[] bytes , int viewWidth , int viewHeight){
            return decodeBitmapByBytes(null,bytes,viewWidth,viewHeight);
        }
    
        public static Bitmap decodeBitmapByBytes(BitmapCache cache , byte[] bytes , int viewWidth , int viewHeight){
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeByteArray(bytes,0,bytes.length,options);
            dealOptions(cache,options,viewWidth,viewHeight);
            Bitmap candidate = BitmapFactory.decodeByteArray(bytes,0,bytes.length,options);
            if(cache!=null) {
                cache.setCandidate(candidate);
            }
            return candidate;
        }
    
        public static Bitmap decodeBitmapByInputStream(InputStream inputStream , int viewWidth , int viewHeight){
            return decodeBitmapByInputStream(null,inputStream,viewWidth,viewHeight);
        }
    
        public static Bitmap decodeBitmapByInputStream(BitmapCache cache , InputStream inputStream , int viewWidth , int viewHeight){
            try {
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inJustDecodeBounds = true;
                FileDescriptor fileDescriptor = ((FileInputStream)inputStream).getFD();
                BitmapFactory.decodeFileDescriptor(fileDescriptor,null,options);
                dealOptions(cache,options,viewWidth,viewHeight);
                Bitmap candidate = BitmapFactory.decodeFileDescriptor(fileDescriptor,null,options);
                if(cache!=null) {
                    cache.setCandidate(candidate);
                }
                return candidate;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        public static void dealOptions(BitmapCache cache ,BitmapFactory.Options options,int viewWidth , int viewHeight){
            if(canUseForInBitmap(cache,options)){
                options.inMutable = true;
                options.inBitmap = cache.getCandidate();
            }else {
                int bitmapWidth = options.outWidth;
                int bitmapHeight = options.outHeight;
                int inSimpleSize = 1;
                if (bitmapWidth > viewWidth || bitmapHeight > viewHeight) {
                    if (cache!=null && cache.isFixed()) {
                        int halfWidth = bitmapWidth / 2;
                        int halfHeight = bitmapHeight / 2;
                        while (halfWidth / inSimpleSize >= viewWidth &&
                                halfHeight / inSimpleSize >= viewHeight) {
                            inSimpleSize *= 2;
                        }
                    } else {
                        int widthRatio = bitmapWidth / viewWidth;
                        int heightRatio = bitmapHeight / viewHeight;
                        if (widthRatio >= 1 && heightRatio >= 1) {
                            inSimpleSize = Math.min(widthRatio, heightRatio);
                        }
                    }
                }
                options.inSampleSize = inSimpleSize;
            }
            options.inJustDecodeBounds = false;
        }
    
        public static boolean canUseForInBitmap(BitmapCache cache ,BitmapFactory.Options options){
            if(cache==null || cache.getCandidate()==null) return false;
            int width = options.outWidth / Math.max(options.inSampleSize,1);
            int height = options.outHeight / Math.max(options.inSampleSize,1);
            int byteCount = width * height * getBytePerPixel(cache.getCandidate().getConfig());
            return byteCount <= cache.getCandidate().getAllocationByteCount();
        }
    
        public static int getBytePerPixel(Bitmap.Config config){
            int bytePerPixel;
            switch (config){
                case ALPHA_8:
                    bytePerPixel = 1;
                    break;
                case RGB_565:
                case ARGB_4444:
                    bytePerPixel = 2;
                    break;
                default:
                    bytePerPixel = 4;
                    break;
            }
            return bytePerPixel;
        }
    
        /***********        获取分片图片      **************/
        
        
        public static Bitmap getPieceBitMapByBytes(byte[] data,int offset, int length, Rect rect){
            try {
                BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(data,offset,length,false);
                return getPieceBitMap(decoder,rect);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        public static Bitmap getPieceBitMapByFileDescriptor(FileDescriptor fd, Rect rect){
            try {
                BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(fd,false);
                return getPieceBitMap(decoder,rect);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        public static Bitmap getPieceBitMapByPathName(String pathName, Rect rect){
            try {
                BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(pathName,false);
                return getPieceBitMap(decoder,rect);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        public static Bitmap getPieceBitMapByInputStream(InputStream inputStream, Rect rect){
            try {
                BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(inputStream,false);
                return getPieceBitMap(decoder,rect);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        public static Bitmap getPieceBitMap(BitmapRegionDecoder decoder, Rect rect){
            BitmapFactory.Options options = new BitmapFactory.Options();
            Bitmap bitmap = decoder.decodeRegion(rect,options);
            return bitmap;
        }
        
    
        public static class BitmapCache{
            private boolean isFixed;
            private Bitmap candidate;
    
            public BitmapCache(boolean isFixed, Bitmap candidate) {
                this.isFixed = isFixed;
                this.candidate = candidate;
            }
    
            public boolean isFixed() {
                return isFixed;
            }
    
            public void setFixed(boolean fixed) {
                isFixed = fixed;
            }
    
            public Bitmap getCandidate() {
                return candidate;
            }
    
            public void setCandidate(Bitmap candidate) {
                this.candidate = candidate;
            }
        }
    }
    

    3.缓存一般用LruCache(内存缓存)和DiskLruCache(磁盘缓存),它们都是采用Lru算法,即近期最少使用算法,缓存不足时会清掉最近最少使用的数据。

    4.LruCache内部采用LinkedHashmap以强引用的方式存储对象,且LruCache是线程安全的,其get、set方法内部都用了synchronized关键字。LruCache对象要重写sizeOf方法,用来完成bitmap的大小计算,父类的sizeof方法默认返回1。存值用mLruCache.put(key,value)方法,取值用mLruCache.get(key)方法。

    5.DiskLruCache的创建要用DiskLruCache.open(File directory,int appVersion,int valueCount,long maxSize)方法创建。directory表示存储路径,如果希望应用卸载的时候删除缓存,那么用SD卡的应用缓存目录,否则就用SD卡的其他目录;appVersion表示版本标识,发生改变时会清空缓存数据,一般来说不需要清就一直设为1;valueCount表示单个节点对应的数据个数,一般设为1;maxSize表示缓存的总大小。

    6.DiskLruCache添加缓存要用Editor来实现,即DiskLruCache.Editor editor = diskLruCache.edit(key),以图片为例,key代表图片的url对应的key,之所以要转成key,是因为图片url中可能有特殊字符,转换规则如下:

    public String getHashKeyFromUrl(String url){
            String cacheKey;
            try {
                MessageDigest messageDigest = MessageDigest.getInstance("MD5");
                messageDigest.update(url.getBytes());
                cacheKey = byteToHexString(messageDigest.digest());
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
                cacheKey = String.valueOf(url.hashCode());
            }
            return cacheKey;
        }
    
        public String byteToHexString(byte[] bytes){
            if(bytes==null){
                return null;
            }
            StringBuilder builder = new StringBuilder();
            int length = bytes.length;
            for(int i=0 ; i<length ; i++){
                String hex = Integer.toHexString(0xFF & bytes[i]);
                if(hex.length()==1){
                    builder.append('0');
                }
                builder.append(hex);
            }
            return builder.toString();
        }
    

    通过Editor得到文件输出流,再往里面写数据,最后通过Editor.commit方法写入缓存。如下:

    DiskLruCache.Editor editor = diskLruCache.edit(getHashKeyFromUrl(url));
                OutputStream outputStream = editor.newOutputStream(0);
                BufferedOutputStream bufferedOutputStream=new BufferedOutputStream(outputStream);
                ByteBuffer byteBuffer=ByteBuffer.allocate(bitmap.getByteCount());
                bitmap.copyPixelsToBuffer(byteBuffer);
                byte[] bytes=byteBuffer.array();
                bufferedOutputStream.write(bytes);
                editor.commit();
                diskLruCache.flush();
    

    7.DiskLruCache取缓存数据要用DiskLruCache.SnapShot,通过它可以拿到FileInputStream对象,然后通过mFileInputStream.getFD()方法拿到FileDescriptor,最后通过BitmapFactory.decodeFileDescriptor(FileDescriptor fd)方法拿到bitmap对象。如下:

    Bitmap bitmap=null;
            try {
                DiskLruCache.Snapshot snapshot=diskLruCache.get(getHashKeyFromUrl(url));
                FileInputStream fileInputStream= (FileInputStream) snapshot.getInputStream(0);
                FileDescriptor fileDescriptor=fileInputStream.getFD();
                bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
            } catch (IOException e) {
                e.printStackTrace();
            }
    

    相关文章

      网友评论

          本文标题:Bitmap的加载和缓存

          本文链接:https://www.haomeiwen.com/subject/upbgaftx.html