图片加载和Cache

图片加载和Cache

----------(我为自己的勤奋感动了!最近项目调整我负责的模块较多,且都是自定义View相关,后面学习了会分享这方面干货)

    今天我和大家分享的是图片的加载以及图片的缓存,项目中我们运用过最多的是图片的加载。假如通过ImageView来显示图片,很多时候ImageView的大小并没有图片大,这样加载不但没有办法显示原始图片而且图片过大还容易出现OOM问题。如何高效的加载Bitmap图片?就是采用BitmapFactory.Options来加载所需的图片大小。

    BitmapFactory.Options来缩放图片,主要是用到inSampleSize(采样率)参数。inSampleSize为1时,采样后的图片大小为图片的原始大小。inSampleSize为2时其图片的宽/高为原图大小的1/2。像素为原图的1/4。故缩放后图片的大小是以采样率2次方形式递减。


eg:以一张1024*768图片为例,采样率为:4

 /**
     * 方法名:decodeSampledBitmap(Resources res,int resId,int reqWidth,int reqHeight)<br>
     * 用    法:用于获取压缩bitmap<br>
     * 参    数:Resources res int resId(资源ID) int reqWidth(请求宽度) int reqHeight(请求高度)<br>
     * 返回值:采样率<br>
     */
    private Bitmap decodeSampledBitmap(Resources res,int resId,int reqWidth,int reqHeight){
    	final BitmapFactory.Options options = new BitmapFactory.Options();
    	options.inJustDecodeBounds = true;//仅获取图片的长宽
    	options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    	options.inJustDecodeBounds = false;//获取图片的长宽以及像素
    	return BitmapFactory.decodeResource(res, resId, options);//根据资源获取图片
    }
    
    /**
     * 方法名:calculateInSampleSize(BitmapFactory.Options options,int reqWidth,int reqHeight)<br>
     * 用    法:用于获取图片采样率<br>
     * 参    数:BitmapFactory.Options options int reqWidth(请求宽度) int reqHeight(请求高度)<br>
     * 返回值:采样率<br>
     */
    public int calculateInSampleSize(BitmapFactory.Options options,int reqWidth,int reqHeight){
    	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;
    }
可见inSampleSize用于图片的压缩大大的减少了我们内存开销,以及流量开销(采样率也可用于加载网络图片压缩后续讲解到)

1.2图片的缓存策略

一般图片缓存我们运用较多的是LruCache(内存缓存),DiskLruCache(储存设备的缓存)。

LruCache是线程安全,且当缓存满时,移除较早使用的缓存对象。

LruCache初始化比较简单:

int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);//当前进程的可用类存转化为KB
		int cacheSize = maxMemory / 8;//大小为当前进程可用类存/8
		mMemoryCache = new LruCache<String, Bitmap>(cacheSize){
			@Override
			protected int sizeOf(String key, Bitmap value) {//重写sizeOf()返回当前图片的大小
				return value.getRowBytes() * value.getHeight() /1024;
			}
		};
LruCache特殊情况下还需要重写LruCache的entryRemoved方法,LruCache移除旧缓存时会调用,此时可以在entryRemoved中完成一些资源的回收工作。

LruCache还支持获取和添加

mMemoryCache.get(key);
mMemoryCache.put(key, value)
用法和简单但是不影响它强大的功能,依靠LinkedHashMap支持访问顺序排序,淘汰最近使用最少缓存原则。

DiskLruCache初始化不能通过构造方法,而是使用它的open方法

 public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
File directory 文件存储路径

int appVersion app版本号,版本号改变DiskLruCache会清空之前所有的缓存文件

int valueCount 对应数据的个数,一般设为1。

long maxSize 缓存总数(eg:50M超过这个大小后DiskLruCache会清除一些缓存)

DiskLruCache 的写入:

private Bitmap loadBitmapFromHttp(String url,int reqWidth,int reqHeight){
		if (Looper.myLooper() == Looper.getMainLooper()) {//这个方法不能在主线程中执行,会抛出异常
			throw new IllegalArgumentException("Looper.myLooper() == Looper.getMainLooper()");
		}
		if (mDiskLruCache == null) {
			return null;
		}
		String key = hashKeyFormUrl(url);//我们一般会用url作为key,但是有时url有特殊字符,故需要将url转为md5的值
		Editor edit = mDiskLruCache.edit(key);//如果此时这个缓存正在编辑则返回null,diskLruCache不允许同时编辑一个缓存
		if (edit != null) {
			OutputStream newOutputStream = edit.newOutputStream(DISK_CACHE_INDEX);//因为前面我设置了对应的数据个数为1此时DISK_CACHE_INDEX为0即//可
			if (downloadUrlToStream (url , newOutputStream)) {
				edit.commit();//提交写入操作
			}else{
				edit.abort();//请求失败回退整个操作
			}
			mDiskLruCache.flush();
		}
		return loadBitmapFromDiskCache(url, reqWidth, reqHeight);
	}

DiskLruCache 的缓存查找:

private Bitmap loadBitmapFromDiskCache(String url,int reqWidth,int reqHeight){
		if (Looper.myLooper() == Looper.getMainLooper()) {
			throw new IllegalArgumentException("Looper.myLooper() == Looper.getMainLooper()");
		}
		if (mDiskLruCache == null) {
			return null;
		}
		
		Bitmap bitmap = null;
		String key = hashKeyFormUrl(url);
		Snapshot snapshot = mDiskLruCache.get(key);//通过key获得一个Snapshot对象
		if (snapshot != null) {
			FileInputStream fileInputStream = (FileInputStream)snapshot.getInputStream(DISK_CACHE_INDEX);//获得输入流
			FileDescriptor fd = fileInputStream.getFD();
			bitmap = mImageResizer.decodeSampleBitmapFromFileDescriptor(fd,reqWidth,reqHeight);
			
		}
		return bitmap;

图片的缓存Cache使用讲解结束了,如果读者想详细了解他们源码可上网查询。后面我会讲解一个具有图片的同步加载,图片的异步加载,图片压缩,磁盘缓存,网络拉取优秀的ImageLoad是怎么结合使用图片的Cache的。

谢谢品读!!





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值