Android学习笔记(一)------Bitmap 位图

Android学习笔记(一)------Bitmap 位图

背景:

无论任何App的开发都离不开图片的加载,通常图片加载有三种方式:资源项目图片,本地图片和网络图片资源等。通常采用ImageView作为载体,设置ImageView的相应的API来显示图片内容。

例如:通过ImageView的setImageResource(int id)方法来显示资源项目图片内容,但是有一个问题,加入我们使用的图片是来自于本地或者网络资源,又该如何呢?

所有引入第一个问题:如何实现从本地或者网络资源上显示图片?这个时候可能会想到一个更深的问题,那就是图片是以怎样的方式在Android中显示。此时引入第二个问题:图片是以怎样的方式显示出来?

都知道,假设使用TextView来显示本地一个文本内容,只需要将该文件创建并包装成一个输入流对象,通过该输入流对象获取代表文本内容的字符串对象,最后通过TextView的相应API来显示文本内容。但是,如果要加载图片呢?实际上会发现,图片内容无法通过字符串来表示(你可以通过文字描述完整表达出一张图片吗?)。

我们都知道,一个面就由无数个点构成,同样道理,一张图片也是有无数个像素点有序连接构成。即图片的内容就是无数的有序像素点。在此回答第二个问题:实际上实现图片的显示都是通过 “在内存中加载图片内容—>从内存中将内容表达出来” ,这时候会想到,怎么才可以将图片内容在内存中表示出来呢?这个时候回答第一个问题:那就是,Bitmap(位图)。

概念描述:

Bitmap(位图):本质是图片在内存中表达形式。都知道面由无数的点构成,但是对于图片来说,没有必要用无数的像素点进行图片表达,其一无数的像素点信息量太大无法存储,其二由于人类的肉眼能力有限,我们只需要将图片内容以 有限但足够多 的形式表达出来即可,“无限–>有限”,将图片的内容表达成 有限但足够多的像素点的集合,只需要对这些像素点进行存储便可以将整张图片在内存中表达出来。

像素信息:

每一个像素点都包含了图片的信息,但无非就四个ARGB通道。其中A代表的是 透明度,RGB代表的是 红绿蓝 三种颜色通道,每一个通道的取值范围0~255,即256种取值方式,刚好通过一个字节(8bit)进行表达。所以一个通道为一字节,一个像素点以4字节在内存中表示出来。

但是,在现实中,一张图片的就包含了许多的像素点,而同时也存储了大量的图片,这必然带来了存储空间占用过大问题,其次有些时候,我们也不需要A(透明度)值,例如全家福,婚纱照等,除了我们需要将图片设置为背景时候,否者一般情况这个值是毫无愿意的。所以实际上A值也是要根据实际情况来设定的。

总结:Bitmap对象实际就是图片在内存中表达形式,它将图片在内存中表达成 有限足够多的像素点的集合,每一个像素点都包含了所在的像素点信息即ARGB,确定每一个像素点的ARGB值,也就确定好了图片的内容。

所以,Android图片加载无论以哪种方式,都是先将图片的内容加载到内存中,在通过ImageView对应API来展现图片的内容。

Bitmap.comfig:

comfig为Bitmap的枚举内部类,表示了每个像素点ARGB的存储方案:
ARGB_8888:表示每个通道为8bit,每个像素点4字节,此方案存储图盘质量最高,但占用空间大。
ARGB_4444:表示每个通道4bit,每个像素点2字节,占用空间小,但图片质量低。
ARGB_565:没有A值通道存储,RGB通道分别占5.6.5位。不支持透明值,每个像素点2字节。
ALPHA_8:不支持颜色通道,只支持透明值,用途特殊。

Bitmap的压缩存储:

Bitmap是在内存中表达方式,如果要Bitmap对象的图片内容进行持久化存储为一张图片,则根据不同的压缩算法可以得到不同的图片压缩格式,如JPEG,PNG,GIF等。也就是说,Bitmap是在内存中的表示,JPEG,PNG,GIF等格式图片是持久化存储后的图片。

1.无损压缩:通过扫描图片中重复类容,将重复的内容删除只需要记录好重复区域的起点,无损压缩可以减少压缩后的空间占用,当加载到内存中的时候,重复的区域也会被加载进来,所以无法减少在内存的资源占用。

2.有损压缩:通过把图片中的边缘颜色删除,即使加载到内存中被删除的数据也不会加载进来,减少了内存占用,同时也可以根据情况设置压缩率,但是带来的问题就是图片的内容相对无损压缩会偏低,尤其在高压缩率的情况下。

Bitmap的简单运用:

Bitmap的BitmapFactory(工厂类)提供了四种方法加载图片资源:decodeFile、decodeResource、decodeStream、decodeByteArray。分别是本地图片加载,资源项目图片加载,串流图片加载和字节序列图片加载。举一个例子:例如要从网络上加载图片,需用通过网络请求获得数据串流(输入流对象),依据该流对象使用decodeStream获取一个Bitmap对象,最后通过ImageView的setImageBitmap(Bitmap b)从内存中显示出来。

Bitmap的压缩存储方法:

和加载图片相反,通过compress()方法实现Bitmap的压缩存储,其实质是:
compress(Bitmap.CompressFormat format, int quality, OutputStream stream)

其中,format对象代表的是 压缩后的格式,可以选择PNG,JPEG等。quality对象代表的是 压缩率,其取值范围0~100,100代表无压缩,10代表压缩为原来的10%。stream对象代表的是 某个位置的输出流对象

注意:当设置PNG格式时候无法设置压缩率,原因是PNG属于无损压缩格式。

BitmapFactory.Option类:

BitmapFactory.Option类为Bitmap各个属性设置,当自定义一个Bitmap对象时候,decodeXXX()方法就需要传递一个BitmapFactory.Option对象。

通过BitmapFactory.Option类的构造方法创建出BitmapFactory.Option类对象,该对象包含了Bitmap的各属性的配置信息,如下:

boolean inJustDecodeBounds: 是否只扫描轮廓。
int inSample: 采样率。
** Bitmap.Config inPreferredConfig:** 格式,色彩模式
int outWidth: bitmap对象的宽。
int outHeight: bitmap对象的高。
boolean inDither: 防抖动,默认为false。
boolean inScaled: 是否可以缩放,默认为true。
boolean inMutable: 是否可变,当设为true时,decode转换的方法返回结果全部可以改变。

其中:
一。inJustDecodeBounds属性,当设置为true时,decodeXXX()方法不会分配内存来创建Bitmap对象,会返回一个null;outWidth和outHeight这两个属性只有Bitmap对象创建时才会有值,但如果这时候inJustDecodeBounds属性设置为true,虽然此时不分配内存以创建Bitmap对象,但是扫描轮廓会绕过Bitmap对象的创建来获取Bitmap对象的宽高值。具体的体现在Bitmap的采样率计算。

二。inSample:代表了Bitmap的采样率,默认为1,即一张图片是1920x1080的像素,在默认情况下,加载内存到也是为1920x1080像素,即使采用了ARGB_8888压缩方案,其在内存的大小为192010804/1024/1024约为8M,这只是一张图在内存中的大小,如果当前活动需要加载几十张图片的话,会带来严重的OOM(Out Of memory:即内存溢出)问题。

OOM:虽然当前流行Android设备大小可能达到好几个G,但是在Android中每一个运用其运行内存占用有一个阈值,当超出这个阈值时候,就会发生OOM,可以通过Runtime.getRuntime().maxMemory();来获取当前应用的内存阈值大小。

尽管我们可以通过设置来修改这个运用的阈值,但是要明白,内存属于一种宝贵的资源,不加考虑的给每一个应用提高最大内存阈值是不妥当的,这回带来严重的手机影响影响问题。所以采取提高运用的内存阈值需要慎重考虑才行,不得以滥用。

总言之,Bitmap对象操作属于一种很消耗内存且耗时的操作,尤其在大位图的时候,容易引发OOM错误,但是也有处理方案,那就是利用采样率属性来创建原Bitmap的子采样版本。例如:原图片为1920x1080像素图片,在inSample默认情况下加载内存属于很耗内存,但是如果将inSample值设置为2的时候,图片的宽高尺寸就会变成原宽高的1/2,像素也会随之降低,即使采用ARGB_8888方案,这个时候消耗的内存也比原先的消耗内存为少。

注意的是,设置inSample属性的值时候,设置的值必须为2的幂,如2,4,8等。。。

Bitmap加载的异步问题:

由于我们都知道Bitmap操作属于耗时耗内存的方式,为了避免ANR(应用无法响应)错误,所以在进行Bitmap操作的时候,需要在工作线程执行,获取到Bitmap对象再然后返回主线程UI进行更新设置。

例如:
在这里插入图片描述

知识总结启发,详细的知识总结网址为:
https://www.cnblogs.com/shakinghead/p/11025805.html

最后,写的不好望见谅!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值