关于bitmap的面试详解

一、recycle方法

我们知道bitmap是存储在native内存和Java内存当中的,所以说当它被对象回收的时候,需要分两部分回收,一是回收Java内存中的内存,一就是native中的内存.在3.0以前,我们知道bitmap像素的数据和bitmap的对象是一起存放在堆当中的,所以说,这时候,我们知道,你只要回收堆内存中的内存就可以了,而3.0之后,我们知道它是直接放在内存当中的,你要回收bitmap的时候,它内存其实是不稳定的,这时候官方建议我们用recycle方法,所以recycle方法到底是什么,字面意思我们能猜出来,对bitmap内存的回收.

我来说一下recycle方法的具体意义,

它表示,它在释放这个bitmap内存的时候,它会释放和这个bitmap有关的Native的内存,同时它会清理有关数据对象的引用,,但是这里处理数据的引用并不是立即清理数据.就是说,它不是你调用完这个recycle方法,他就会直接清理这Native个内存,它只是给垃圾回收机制发送一个指令,让它在没有其它对象引用这个bitmap对象的时候,来进行垃圾回收.当调用这个recycle方法之后,这个bitmap就会被标名为"dead"状态,这个时候,你在调用bitmap相关的其它方法,就会引起异常,比如说getPixels()和setPixels(),(这两个方法分别是获取像素,和设置像素)当这些方法调用的时候,它就会引起异常.同时这个recycle操作它是不可逆的,所以说你一定要务必确认好这个bitmap在以后的场景下,不会被你的程序使用到.然后再去谨慎的调用recycle方法,因为你调用recycle方法,这个方法就被标名为死亡状态了,你不能调用它,并且它的任何回调方法.

注意:我们可以不用主动的去调用它,因为我们的垃圾回收机制,当没有其它对象引用,指向该bitmap的时候,它会主动的清理保存.但是我们平时也可以根据特定的场景,去主动的调用recycle方法,当然具体场景,具体分析.

二、LRU算法(又称路由算法)

LRU算法主要用在,我们存储bitmap的时候,用做三级缓存来使用.它的意思就是最近,最少使用的缓冲对象,我们会把它清除出队列.从源码分析一下,我们看出LRU算法其实是一个泛型类,它内部有一个final的LinkedHashMap.

所以它内部是由hashmap来实现的,hashmap它会保持一个强引用的缓冲对象,然后它会提供对应的put,get,resize,remove方法来完成我们的添加移除等操作。在trimToSice里面,这个方法就是说,当它缓冲满的时候,这个算法就会移除较早缓冲对象,然后把新的缓冲对象太添加到队列当中。总之,如果面试官问你,LRU算法是怎么实现的,你可以这么回答:内部它是用一个LinkedHashMap来实现,它里面提供了我们的get和put方法来完成缓冲的添加,和获取操作,当缓冲满的时候,LRU算法它会提供一个trimToSice这个方法,把我们较早的那些缓冲对象移除,添加新的缓冲对象.

接下来我们看一下trimTosice方法

我们可以看到这里做了一个同步代码块的判断,(size <=maxSize),直到里面的元素小于了它的最大值,我们就会退出循环,我们继续往下看,它做出了一个判断计算剩余的size有多少,然后通过不断的循环在if里面做判断 ,如果,小于它的最大值,我们就可以终止循环,移除的时候,我们用的是hashmap的remove方法,remove方法内部调用了removeEntryForKey,其实它也是通过KEY的值,来删除它对应的值,remove方法之后,它会计算一个它的尺寸,它通过"-="号来判断,它会用safeSizeof来计算现在缓冲队列的大小,然后把它减掉,最后底部,它调用的是entryRemoved方法,其实这个方法是空方法,这里面做了什么操作呢?就是说如果你想在LRU算法里面做一些二级缓存的操作,你可以实现这个方法,并且在里面做一下相应的业务逻辑的判断,这就是trimToSize方法.这个方法简单来说:它会删除那些最老的,最不常用的缓冲对象,把他们从队列中移除,同时把最新的,用的最多的缓冲对象添加到缓冲队列当中,这就是trimToSize.

 

三、计算inSampleSize

我们知道Bitmap节省内存有很多种方法,其实最重要的技巧,无非就是在合适的时间加载合适大小的bitmap,我们知道现在的照片都是越来越大,如果你把这些大图加载到内存当中,很容易造成OOM,说明你这个bitmap已经超过了这个APK进程所能容纳的最大的大小,所以说,你不能把每一张照片的原图,加载到内存当中.所以说,这里官方给我们提供了一个合适的缩减的比例,来加载到内存当中.

我们来看这个方法,首先第一步,它会计算原始的长宽高,默认把inSampleSize这个比例设置成1,然后在下面会做一个判断,比较一个最小的inSampleSize值作为inSampleSize.作为我们的缩减比例,这就是官网提供的方法.

四、缩略图的算法

缩略图是和我们inSampleSize是分不开的,主要是根据inSampleSize算出来的值,来相应的保存bitmap到内存当中.

 

我们可以看到这里有一个很重要的属性,叫做inJustDecodeBounds,这个属性是通过bitmapFactory传递过来的,它是说明意思呢?就是说我们先把它nJustDecodeBounds设置为true,这时候我们通过bitmapFactory.decodeFile方法把bitmap加载到内存当中,但是这个时候,它并不是把整个原图加载到内存当中,它只是会计算一个比例.这时候,你再把inJustDecodeBounds设置为false以后,它会通过计算好的缩放比例,把它bitmap放到内存当中,计算出我们缩略图的大小.这也是bitmap优化的一个很重要的方式.大家一定要记住inJustDecodeBounds这个属性,因为面试会常常问到.

五、三级缓存

我们知道现在的APP所有的请求都是需要和网络进行交互的,图片更不用说,包括listView当中的一些大图,如果你每次启动的时候,都从网络上获取图片的话,你肯定会消耗用户的流量,这时候你还要分别用户不同的网络情况,比如说wifi情况下,4G情况下,这时候流量对用户来说是很贵的,如果说你是一个很耗费流量的应用,用户对你这个APP的喜爱程度肯定会受到影响.特别是如果我们重复的去加载某些图片,都要去用网络流量的话,这对用户体验说,是很不好的.所以说,在这个基础上我们提出了三级缓冲的概念.

        三级缓冲到底是有那三级?初略的分析的话,它分为网络,本地和内存三级缓存.这样它就可以为我们减少不必要的网络加载,减少流量的使用.它的原理很简单,比如说:你首次打开你的APP,你要加载一些图片,这时候你肯定只能从网络上获取,当你从网络上加载完图片之后,你会把你的图片保存到SD卡.和你相应的内存当中各一份.这个时候你如果要再次请求同一个URL的bitmap的时候,你就不用从网络上获取了,这时候从你的内存或者本地获取就可以了,这就是三级缓冲总体的一个概念.

      三级缓冲有那些优缺点呢?

  • 网络加载,不优先加载,速度慢,浪费流量
  • 本地缓存,次优先加载,速度快
  • 内存缓存,优先加载,速度最快
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值