美文网首页
Bitmap加载和缓存策略

Bitmap加载和缓存策略

作者: android小菜鸡一枚 | 来源:发表于2018-08-15 09:48 被阅读0次
    Bitmap加载

    BitmapFactory提供了四类方法:decodeFile,decodeResource,decodeStream,decodeByteArray,分别用于支持从文件系统,资源,输入流以及字节数组中加载一个Bitmap对象。
    采用BitmapFactory.Options缩放图片可以高效加载Bitmap,其inSampleSize参数即采样率
    获取采样率?
    1.将BitmapFactory.Options的inJustDecodeBounds参数设为true并加载图片
    2.从BitmapFactory.Options中取出图片的原始宽高信息,他们对应于outWidth和outHeight参数
    3.根据采样率的规则并结合目标View的所需大小计算出采样率inSampleSize
    4.将BitmapFactory.Options的inJustDecodeBounds参数设为false,然后重新加载图片。

    public static Bitmap decodeSamledBitmapFromResource(Resource res,int resId,int reqWidth,int reqHeight) {
        // First decode with inJustDecodeBounds = true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res,resId,options);
        // calculate inSamleSize
        options.inSampleSize = calculateInSampleSize(options,reqWidth,reqHeight);
        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res,resId,options);
    }
    
    public static int calculateInSampleSize(
          BitmapFactory.Options options,int reqWidth,int reqHeight){
        //Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        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;
    }
    
    mImageView.setImageBitmap(decodeSamledBitmapFromResource(getResources(),R.id.myimage,100,100));
    
    Android中的缓存策略

    当程序第一次从网络加载图片后,就将其缓存到存储设备上,这样下次使用这张图片就不用从网络上获取了,节省流量;很多时候为了提高应用的用户体验,往往还会把图片在内存中再缓存一份,这样应该打算从网络上请求一张图片时程序首先会从内存中去获取,如果内存中没有那就从存储设备中获取,如果存储设备中也没有,那就从网络下载这张图片。
    缓存策略主要包含缓存的添加,获取和删除这三类操作。
    缓存算法LRU(Least Recently Used),LRU是近期最少使用算法,核心思想是当缓存满时,会优先淘汰那些近期使用的缓存对象。LRU算法的缓存有两种:LruCache和DiskLruCache,Lru用于实现内存缓存,而DiskLruCache实现存储设备缓存。

    LruCache

    强引用:直接的对象引用
    软引用:但一个对象只有软引用存在时,系统内存不足时此对象会被gc回收
    弱引用:当一个对象只有弱引用存在时,此对象会随时被gc回收
    LruCache是一个泛型类,它内部采用一个LinkedHashMap以强引用的方式存储外界的缓存对象,其提供了get和put方法来完成缓存的获取和添加操作,当缓存满时,LruCache会移除较早使用的缓存对象,然后添加新的缓存对象。LruCache是线程安全的

    int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
    int cacheSize = maxMemory / 8;
    mMemoryCache = new LruCache<String,Bitmap>(cacheSize) {
        @Override
        protected int sizeOf(String key,Bitmap bitmap) {
            return bitmap.getRowBytes()*bitmap.getHeight() / 1024;
        }
    }
    //从LruCache中获取一个缓存对象
    mMemoryCache.get(key)
    //向LruCache中添加一个缓存对象
    mMemoryCache.put(key,bitmap)
    
    DiskLruCache

    磁盘缓存,通过将缓存对象写入文件系统,从而实现缓存的效果。
    DiskLruCache的创建过程

    private static final long DISK_CACHE_SIZE = 1024* 1024 * 50;//50MB
    File diskCacheDir = getDiskCacheDir(mContext,"bitmap");
    if(!diskCacheDir.exists()) {
        diskCachDir.mkdirs();
    }
    mDiskLruCache = DiskLruCache.open(diskCacheDir,1,1,DISK_CACHE_SIZE);
    

    DiskLruCache的缓存添加
    DiskLruCache的缓存添加的操作是通过Editor完成的,Editor表示一个缓存对象的编辑对象;首先需要获取图片url所对应的key,然后根据key就可以通过edit()来获取Editor对象,一般采用url的MD5作为key。

    private String hashKeyFormUrl(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());
        }
        return cacheKey;
    }
    
    private String bytesToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<bytes.length;i++){
            String hex = Integer.toHexString(0xFF & bytes[i]);
             if(hex.length() == 1) {
                sb.append('0');
             }
            sb.append(hex);
        }
        return sb.toString();
    }
    
    //将图片的url转成key以后,就可以获取Editor对象了
    String key = hashKeyFormUrl(url);
    DiskLruCache.Editor editor = mDiskLruCache.edit(key);
    if(editor!=null){
        OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX);
    }
    
    ImageLoader实现

    内存缓存和磁盘缓存是ImageLoader的核心,只有当这两级缓存都不可用时才需要从网络中拉取图片。
    首先尝试从内存缓存中读取图片,接着尝试从磁盘缓存中读取图片,最后从网络中拉取图片。
    图片压缩
    内存缓存和磁盘缓存
    选择线程池和Handler来提供ImageLoader的并发能力和访问UI的能力。

    《Android开发艺术探讨》Bitmap的加载和Cache

    相关文章

      网友评论

          本文标题:Bitmap加载和缓存策略

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