Bitmap整理
Bitmap.getAllocationByteCount() 方法获取 Bitmap 占用的字节大小 默认情况下 BitmapFactory 使用 Bitmap.Config.ARGB_8888 的存储方式来加载图片内容,而在这种存储模式下,每一个像素需要占用 4 个字节。 实际上 BitmapFactory 在解析图片的过程中,会根据当前设备屏幕密度和图片所在的 drawable 目录来做一个对比,根据这个对比值进行缩放操作。 在 Android 中,各个 drawable 目录对应的屏幕密度分别为下: PS: Options.inMutable 置为 true,这里如果不置为 true 的话,BitmapFactory 将不会重复利用 Bitmap 内存 复用 inBitmap 之前,需要调用 canUseForInBitmap 方法来判断 reuseBitmap 是否可以被复用。这是因为 Bitmap 的复用有一定的限制: 在不压缩图片的前提下,不建议一次性将整张图加载到内存,而是采用分片加载的方式来显示图片部分内容,然后根据手势操作,放大缩小或者移动图片显示区域。 BitmapRegionDecoder 将图片加载到内存中,图片可以以绝对路径、文件描述符、输入流的方式传递给 BitmapRegionDecoder 当需要在界面上同时展示一大堆图片的时候,比如 ListView、RecyclerView 等,由于用户不断地上下滑动,某个 Bitmap 可能会被短时间内加载并销毁多次。这种情况下通过使用适当的缓存,可以有效地减缓 GC 频率保证图片加载效率,提高界面的响应速度和流畅性。 LruCache(Least Recently Used)算法的核心思想就是 最近最少使用算法 。 内部维护了一个 LinkHashMap 的链表,通过put数据的时候判断是否内存已经满了,如果满了,则将最近最少使用的数据给剔除掉,从而达到内存不会爆满的状态。
Bitmap的原理
在网上有一道面试题大概意思就是: 存在十亿个数字,现在需要知道哪些数字没有出现在里面. 这个问题你可能觉得一个for循环就能解决,但是实际上你可能忽略了一个问题,那就是10亿个数字需要占据的内存空间.例如在java中要存下10亿个数字需要多大空间呢?假设使用int存储,一个int占32个位也就是4个字节.存放10亿个数字则需要: 10亿*4/1024/1024/1024 = 4G左右 .面对上面的问题我们肯定不能使用这种方式存储.而使用我们的Bitmap就能很好的解决上面的问题.
Bitmapi简单的说就是使用bit(位)来存储状态,适合用来存储大规模的数据,但是状态又不是很多的情况.举例来说,如果我现在有 1,3,4,2,7 这五个数字,如果我们使用5个int来存储则需要20个字节的空间.但是我现在使用1字节就能存储上面的五个数字.如下图所示,1个字节可以用8位表示,1位有0和1两种值分别用来表示该位上是否有值,而位的索引用来表示数字(图中以从左到右的顺序计算).
而它的缺点同样也比较明显.它的一个位只能存储一个数据,对于重复的数据无法记录.如果数据分布很稀疏,会造成空间的浪费.例如,如果现在只有{1,3,1000000000}这个三个数据,它有很多空间会被浪费掉.
BitMap在java中提供了BitSet的实现,同时在我们平常使用的Redis中也有实现.它很适合用来做大量的用户统计.例如统计登录人数,签到,在线等等.这些需求都可以通过redis的bit相关指令很简单的就能实现.
例如,统计网站的在线人数:
上面的方式不仅简单,而且就算用户数量很大也能又快又好的完成.
bitmap设置图片大小-Android内存优化五:Bitmap优化
C#wpfBitmapImage从本地资源获得未知像素大小的图片,如何将其对象设为指定大小一般来说一个点被精确的认定为1/72英寸,在WPF中,采用的设备无关单位即1/96英寸所以程序中获取的图片大小比真实图片的大小要大一点,获取到图片大小后进行相应的转换即可获得图片原来的尺寸如:height=height*72/96bmp全屏截图大小800*480。在任意位置显示任意大小bmp图片头文件,普通全屏800*480显示bmp,容易分析。BMP(全称Bitmap)是Windows操作系统中的标准图像文件格式,可以分成两类:设备有向量相关位图(DDB)和设备无向量相关位图(DIB),使用非常广。Android内存优化五:Bitmap优化Android内存优化一:java垃圾回收机制Android内存优化二:内存泄漏Android内存优化三:内存泄漏检测与监控Android内存优化四:OOMAndroid内存优化五:Bitmap优化压缩比:scale=(flaot)targetDensity/densitytargetDensity:设备屏幕像素密度dpidensity:图片对应的文件夹的像素密度dpi1)、同一张图片放在不同的资源目录下,其分辨率会有变化。2)、Bitmap的分辨率越高,其解析后的宽高越小,甚至小于原有的图片(及缩放),从而内存也响应的减少。3)、图片不放置任何资源目录时,其使用默认分辨率mdpi:160。4)、资源目录分辨率和屏幕分辨率一致时,图片尺寸不会缩放。Bitmap放在资源目录中的计算方式为:主要通过编码、采样、复用、匿名共享区进行优化由于ARGB_4444的画质惨不忍睹,一般假如对图片没有透明度要求的话,可以改成RGB_565,相比ARGB_8888将节省一半的内存开销其中,A代表透明度;R代表红色;G代表绿色;B代表蓝色。ALPHA_8表示8位Alpha位图,即A=8,一个像素点占用1个字节,它没有颜色,只有透明度。ARGB_4444表示16位ARGB位图,即A=4,R=4,G=4,B=4,一个像素点占4+4+4+4=16位,2个字节。ARGB_8888表示32位ARGB位图,即A=8,R=8,G=8,B=8,一个像素点占8+8+8+8=32位,4个字节。RGB_565表示16位RGB位图,即R=5,G=6,B=5,它没有透明度,一个像素点占5+6+5=16位,2个字节。bitmap的占用内存,是以bitmap的宽高和每个像素占用的字节数决定的。根据BitmapFactory的采样率进行压缩设置采样率,不能小于1假如是2则宽为之前的1/2,高为之前的1/2,一共缩小1/4以此类推图片复用指的是inBitmap这个属性。不使用这个属性,你加载三张图片,系统会给你分配三份内存空间,用于分别储存这三张图片如果用了inBitmap这个属性,加载三张图片,这三张图片会指向同一块内存,而不用开辟三块内存空间。inBitmap的限制:1、3.0-4.3复用的图片大小必须相同编码必须相同2、4.4以上复用的空间大于等于即可编码不必相同3、不支持WebP4、图片复用,这个属性必须设置为true;=true;Android系统为了进程间共享数据开辟的一块内存区域,由于这块区域不受应用的Head的大小限制,相当于可以绕开oom,FaceBook的Fresco首次应用到实际中。限制:5.0以后就限制了匿名共享内存的使用。在SDK11->18之间,重用的bitmap大小必须是一致的,例如给inBitmap赋值的图片大小为100-100,那么新申请的bitmap必须也为100-100才能够被重用。从SDK19开始,新申请的bitmap大小必须小于或者等于已经赋值过的bitmap大小。新申请的bitmap与旧的bitmap必须有相同的解码格式,例如大家都是8888的,如果前面的bitmap是8888,那么就不能支持4444与565格式的bitmap了。我们可以创建一个包含多种典型可重用bitmap的对象池,这样后续的bitmap创建都能够找到合适的“模板”去进行重用。8.0Bitmap的像素数据存储在Native,为什么又改为Native存储呢?因为8.0共享了整个系统的内存,测试8.0手机如果一直创建Bitmap,如果手机内存有1G,那么你的应用加载1G也不会oom。可以利用LRU开管理Bitmap,给他设置内存最大值,及时回收。BitmapRegionDecoder
Android中Bitmap和BitmapDrawable有什么不同
Bitmap继承Parcelable,是一个可以跨进程传输的对象,BitmapDrawable继承Drawable,可Drawable只是一个抽象类,此类是一个存放数据流的载体。
1.使用情况:如果想绑定imageView之类的控件,两者都可以用,而想要将图片数据转换成其它对象,Bitmap功能更强大,而BitmapDrawable只是一个流的载体,所以一般获取src资源文件的时候用得多,而想要把资源图片截入到Bitmap需要转换后才可得到Bitmap对象。
2.BitmapDrawable就是封装了一个位图。直接以文件的方式,就是封装了一个原始的位图。以Xml方式,可以对原始的位图进行一系列的处理,比如说抗锯齿,拉伸,对齐等等。
3.要了解BitmapDrawable的使用,还需要明白Bitmap、BitmapFactory等类。Bitmap代表了一个原始的位图,并且可以对位图进行一系列的变换操作。BitmapFactory提供一系列的方法用于产生一个Bitmap对象。多用在Canvas中。
android bitmap 使用时候注意什么
一、 问题的背景和意义
在Android移动应用开发中,对Bitmap的不小心处理,很容易引起程序内存空间耗尽而导致的程序崩溃问题。比如我们常遇到的问题:
java.lang.OutofMemoryError: bitmap size exceeds VM budget.
导致该问题的出现,一般由以下几方面原因导致:
引动设备一般存储空间非常有限。当然不同设备分配给应用的内存空间是不同的。但相对不但提高的设备分辨率而言,内存的分配仍然是相对紧张的。
Bitmap对象常常占用大量的内存空间,比如:对于2592*1936的设备,如果采用ARGB_8888的格式加载图像,内存占用将达到19MB空间。
在Anroid App中经常用到ListView,ViewPager等控件,这些控件常会包含较大数量的图片资源。
二、 问题及场景分析
1 高效地加载大图片。
BitmapFactory类提供了一些加载图片的方法:decodeByteArray(), decodeFile(), decodeResource(), 等等。
为了避免占用较大内存,经常使用BitmapFactory.Options 类,设置inJustDecodeBounds属性为true。
//
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds =true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
为了避免java.lang.OutOfMemory 的异常,我们在真正decode图片之前检查它的尺寸,除非你确定这个数据源提供了准确无误的图片且不会导致占用过多的内存。
加载一个按比例缩小的版本到内存中。例如,如果把一个原图是1024*768 pixel的图片显示到ImageView为128*96 pixel的缩略图就没有必要把整张图片都加载到内存中。为了告诉解码器去加载一个较小的图片到内存,需要在你的BitmapFactory.Options 中设置 inSampleSize 为true 。例如, 一个分辨率为2048x1536 的图片,如果设置inSampleSize 为4,那么会产出一个大概为512x384的图片。加载这张小的图片仅仅使用大概0.75MB,如果是加载全图那么大概要花费12MB(假设bitmap的配置是ARGB_8888).
2 不要在主线程处理图片。
众所周知的问题,不再赘述。
注意两点:1. 为了保证使用的资源能被回收,建议使用WeakReference, 以应用内存内存紧张时,回收部分资源,保证程序进程不被杀死。
2. 避免异步任务的长时间耗时操作,在任务执行结束后,及时释放资源。
3 管理Bitmap内存。
在Android开发中,加载一个图片到界面很容易,但如果一次加载大量图片就复杂多了。在很多情况下(比如:ListView,GridView或ViewPager),能够滚动的组件需要加载的图片几乎是无限多的。
有些组件的child view在不显示时会回收,并循环使用,如果没有任何对bitmap的持久引用的话,垃圾回收器会释放你加载的bitmap。这没什么问题,但当这些图片再次显示的时候,要想避免重复处理这些图片,从而达到加载流畅的效果,就要使用内存缓存和本地缓存了,这些缓存可以让你快速加载处理过的图片。
3.1 内存缓存
内存缓存以牺牲内存的代价,带来快速的图片访问。LruCache类(API Level 4之前可以使用Support Library)非常适合图片缓存任务,在一个LinkedHashMap中保存着对Bitmap的强引用,当缓存数量超过容器容量时,删除最近最少使用的成员(LRU)。
注意:在过去,非常流行用SoftReference或WeakReference来实现图片的内存缓存,但现在不再推荐使用这个方法了。因为从Android 2.3 (API Level 9)之后,垃圾回收器会更积极的回收soft/weak的引用,这将导致使用soft/weak引用的缓存几乎没有缓存效果。顺带一提,在Android3.0(API Level 11)以前,bitmap是储存在native 内存中的,所以系统以不可预见的方式来释放bitmap,这可能会导致短时间超过内存限制从而造成崩溃。 收起