您的位置:首页 > 其它

Bitmap的加载和Cache

2018-03-20 21:59 387 查看
    本次主要是包含3个方面的内容,首先讲述如何有效的加载一个bitmap。由于bitmap特殊性以及Android对单个应用所施加的内容限制。这个导致加载bitmap的时候很容易出现内存溢出。    java.lang.OutOfMemoryError:bitmap size exceeds VM budget.    根据上述情况,在android开发中需要经常对bitmap做缓存,通过缓存策略,我们不需要每次都从网络上请求图片或者从内存中加载图片,会极大的提高加载效率以及产品的用户体验。目前常用的缓存策略是LruCache和DiskLruCache。其中LruCache被看做是内存缓存,DiskLruCache被看做是存储缓存。通俗的来说就是:最少使用算法。算法的核心思想:    当缓存快满的时候,会淘汰近期最少使用的缓存目标,很显然Lru算法的思想是很容易被接受的。
Bitmap的高校加载:
    这个介绍biemap的高效加载之前,先说一下如何加载一个biemap。BitmapFactory类提供了四类方法:decodeFile、decodeRessource、decodeStream和decodeByteArray,分别是用于支持从文件系统、资源、输入流以及字节数组中加载出一二Bitmap对象。    如何高效的加载一个Bitmap对象:其实核心思想也很简单,那就是采用BitmapFactory.Options来加载所需尺寸的图片。通过inSampleSize()可以获取到采样率来加载缩小后的图片,将缩小后的图片在对应的位置显示,这样会降低内存占用从而在一定程度上避免OOM。提高了加载时的性能。    inSampleSize方法的值为1的时候,表示采样后的图片大小为图片的原始大小,当值为2的时候:
公式:    采样后的图片大小其宽/高均为原图大小的1/2,像素数为原图的1/4
通过采样率就能有效的加载图片,那么到底如何获取采样率:    (1)将BitmapFactory.Options的inJustDecodeBounds参数设为true并加载图片。    (2)BitmapFactory.Options中获取图片的原始宽高信息,它们对应于outWidth和outHeight参数。    (3)根据采样率的规则结合目标view的所需大小计算出采样率inSampleSize。    (4)将BitmapFactory.Options的inJustDecodeBounds参数设为false,然后冲洗加载图片。将上面的四个流程用程序来实现,如下:

Android中的缓存策略:    缓存的机制:        当程序第一次从网上加载图片后,就将其缓存到内存设备上,这样下次使用这张图片就不用再从网络上获取了,这样就节省了用户的流量,提高了应用的用户体验。往往还会把图片在内存中再缓存一份,这样当应用打算从网络上请求一张图片的时,程序会先从内存中获取,如果内存设备中也没有,就从存储设备中获取,如果存储设备也没有,那就从网络上获取。    目的:        内存中加载图片比在存储中加载图片要快。既提高了程序的效率又为用户节省了不不必要的流量开销。
    缓存策略主要包含缓存的添加、获取和删除三类操作。        添加:        获取:        删除:缓存是有大小的,所以会有删除的操作。
LRU算法:    概念:常用的缓存算法,LRU是近期最少使用算法。核心思想就是当缓存满时,会优先淘汰近期使用最少的缓存对象。LRU算法的缓存有两种:LurCache和DiskLruCache,LurCache用于实现内存缓存,DiskLruCache则充当了存储设备缓存。
LurCache:    LurCache是android3.1提供的缓存类,通过support-V4兼容包可以兼容到早期的android版本。    LurCache是一个泛型类,内部采用LinkedHashMap以强引用的方式存储外界的缓存对象。提供了get和put方法来完成缓存的获取和添加操作。public class LruCache<K, V> {private final LinkedHashMap<K, V> map;    初始化:    /**         * LruCache的创建         * return:    返回的是位图每一行 所占用的空间数*位图的行数            *             最后除以1024得到的是KB。         */        int maxMemory = (int)(Runtime.getRuntime().maxMemory()/1024);        //总容量的大小为当前进程的可用内存的1/8,单位是KB。        int cacheSize = maxMemory/8;        LruCache<String,Bitmap>linkedHashMap = new LruCache<String,Bitmap>(cacheSize){            @Override            protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getRowBytes()*bitmap.getHeight()/1024;            }        };
    获取:linkedHashMap .get(key);    添加:linkedHashMap.put(key,bitmap);    删除:linkedHashMap.remove(key);
DiskLruCache:    概念:DiskLruCache用于实现存储设备缓存,即磁盘缓存,他通过将缓存对象写入文件系统从而实现缓存效果。
    创建:        public static DiskLruCache open(File directory,int appVersion,iint valueCount,long maxSize)                private static final long Disk_cache_size = 1024*1024*50;  //50MB        File diskCacheDir = getDiskCacheDir(mContent,"bitmap");        if(!diskCacheDir.exists()){            diskCacheDir.mkdirs();        }            mDiskLruCache = DiskLruCache.open(diskCacheDir,1,1,DISK_CACHE_SIZE);
    添加:
        private String hashKeyFormurl(String url) {        String cacheKey;        try {
            MessageDigest mDigest = MessageDigest.getInstance("MD5");            mDigest.update(url.getBytes());            cacheKey = bytesToHexString(mDigest.digest());        } catch (Exception e) {            cacheKey = String.valueOf(url.hashCode());        }        return cacheKey;
    }
    private String bytesToHexString(byte[] digest) {        StringBuilder sb = new StringBuilder();        for (int i = 0; i < digest.length; i++) {            String hex = Integer.toHexString(0xff & digest[i]);            if(hex.length() == 1){                sb.append('0');            }            sb.append(hex);        }        return sb.toString();    }
    调用:    String key = hashKeyFormUrl(url);    DiskLruCache.Editor editor = mDiskLruCache .edit(key);    if(editor != null ){        OutPutStream ops = editor.newOutPutStream(DISK_CACHE_INDEX);    }
    当从网络下载图片时,图片流可以通过这个文件输入流写入到文件系统上,实现代码如下:    public boolean downloadUrlToStream(String urlString,            OutputStream outputStream) {        try {            URL url = new URL(urlString);            urlConnection = (HttpURLConnection) url.openConnection();            in = new BufferedInputStream(urlConnection.getInputStream(),                    IO_BUFFER_SIZE);            out = new BufferedOutputStream(outputStream, IO_BUFFER_SIZE);            int b;            while ((b = in.read()) != -1) {                out.write(b);            }            return true;        } catch (Exception e) {            // TODO: handle exception        } finally {            if (urlConnection != null) {                urlConnection.disconnect();            }            try {                in.close();                out.close();            } catch (IOException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }        return false;    }
    调用:    OutputStream outputStream = Editor.newOutPutStream(DISK_CACHE_INDEX);    if(downloadUrlToStream(url,outputStream)){        editor.commit();    }else {         editor.abort();    }    mDiskLruCache.flush();
上述代码,图片已经被正确的写入到文件系统中了,
缓存查找:    通过DiskLruCache方法的get方法得到一个Snapshot对象,紧接着通过Snapshot得到一个文件输入流,自然就能得到bitmap对象了。为了避免OOM,需要参考前面所说的,对图片进行缩放处理,再予以显示,事例代码如下显示:    String key = hashKeyFormurl(url);        try {            DiskLruCache.Snapshot snapshot = mDiskLruCache.get("key");            if (snapshot != null) {                FileInputStream fileInputStream = (FileInputStream) snapshot                        .getInputStream(DISK_CACHE_INDEX);                FileDescriptor fileDescriptor = fileInputStream.getFD();                Object mImageResizer;                Bitmap bitmap = mImageResizer                        .decodeSampleBitmapFromFileDescriptor(fileDescriptor,                                reqWidth, reqHeight);                if (bitmap != null) {                    addBitmapToMemoryCache(key,bitmap);                }            }        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: