但之前理解过很多,所以这里只写之前没有遇到过的。
下面是Options常用的部分成员变量:
public boolean inJustDecodeBounds;
public int inSampleSize;
public int inDensity;
public int inTargetDensity;
public int inScreenDensity;
public boolean inScaled;
public Bitmap.Config inPreferredConfig;
public int outWidth;
public int outHeight;
public String outMimeTye;
其中以in开头的就是设置某某参数,以out开头的就是获取某某参数,比如outWidth就是获取Bitmap的宽。
(1)inJustDecodeBounds 获取图片信息
如果将这个字段设置为true,则表示只解析图片信息,不获取图片、不分配内存,能获取的信息有图片的宽高、MIME。宽高通过outWidth outHeight返回,MIME通过outMimeType返回。
我们在压缩图片时就会经常使用这个字段。一般而言,图片过大时,经常会造成OOM。所以,当图片的尺寸大于我们想要的尺寸时,我们就要进行压缩。这个问题的关键在于,如何不将图片加载到内存中,依然可以知道它的尺寸?而这个参数就很好的完成了这个需求。
我们只需将inJustDecodeBounds设置为true,而不需要将图片加载到内存中,就可以得知它的宽高,然后跟我们想要的尺寸进行对比,进行压缩。
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.avator_xizuka, options);
Log.d(TAG, “bitmap:” + bitmap);
Log.d(TAG, “realwidth:” + options.outWidth + " realheight:" + options.outHeight
- " mimeType:" + options.outMimeType);
可以得出下面打印信息:
看到bitmap为null,但是realwidth和realheight和mimeType都是有值的,这说明没有获取到图片,只是解析了它。
解析是不会占用任何内存的。
(2)inSampleSize
就是采样率,balabalabala
这里有一点,比如ImageView是100_100 而图片像素时300_400 这个时候我们要图片缩小3倍还是4倍呢
因为inSampleSize本来就是失真处理,所以尽量让失真效果没那么强,这里就是缩小3倍的。(举个例子,也不能设inSampleSize为3的)
(3)加载一个Bitmap文件究竟需要占多少空间
之前说过 Bitmap所占的内存是 “宽 * 高 * 4” (因为Bitmap现在都默认ARGB_8888了所以为4字节)
但是这个公式是不是就是一定适用于所有Android机 所有情况呢?
其实不是。根本原因是屏幕的适配。
在Android最初版本的时候,设计人员就考虑到了以后Android以后会有许许多多的不同分辨率的屏幕,所以就定制了几个比如drawable-ldpi drawable-mdpi。。。资源文件,当图片符合该分辨率,就不用进行拉伸或者压缩,但是dpi不止那么几个啊,市面上的不同dpi手机太多了,肯定有图片和该这些分辨率文件不一致,所以,Android就会对该Bitmap进行动态的拉伸/压缩。
比如一张图片在SD卡下的原图是600_800 在Activity使用加载该图片后的内存是2MB,然后将它放入到Drawable-xhdpi下,发现它的宽高被拉伸到了960_1200 这个时候通过Activity加载图片就是4MB多了。
总结:
-
不同名称的资源文件是为了适配不同的分辨率,当屏幕分辨率与文件所在资源文件加对应的分辨率相同时,会直接使用图片,否则会对图片进行缩放。
-
当从本地文件SD卡或者内存中加载图片时,不会对图片进行缩放。
(4)inScaled、inDensity、inTargetDensity、inScreenDensity
- inScaled
只有在一种情况下才会对Bitmap进行拉缩放:就是当图片所在资源文件夹所对应的屏幕分辨率与真实显示的屏幕分辨率不同时。
而这个参数表示,在需要缩放时,是否对当前文件进行缩放。如果inScaled设置为false,则不进行缩放,如果设置为true或者不设置,则会对Bitmap进行动态的缩放。
- inDensity
用于设置文件所在资源文件夹的屏幕分辨率
- inTargetDensity
表示真实显示的屏幕分辨率
- inScreenDensity
真实的分辨率,不过该参数很鸡肋,源码中也没有出现过。就很尴尬。
一张图片的缩放比例在这里就是 scale = inTargetDensity / inDensity
所以这两个参数的作用就是:手动设置文件所在资源文件夹的分辨率和真实显示的屏幕分辨率来指定图片的缩放比例。
(5)inPreferredConfig
用来设置存储格式的。可以设置ARGB_8888、RGB_565。。。
4、创建Bitmap方法之二:静态方法
除了用BitmapFactory.decodeXXX函数来加载图片,还可以通过Bitmap自带的静态方法加载图片
就是 createBitmap(...)
createScaledBitmap(...)
createBitmap 的构造函数很多,但都容易理解,这里就不再讲解。
来看下createScaledBitmap(Bitmap src,int dstWidth,int dstHeight,boolean filter)
其中Bitmap src表示要缩放的源图像,dstWidth dstHeight表示缩放后的目标宽高,filter表示是否给图像添加滤波效果
到这里,有关创建Bitmap的方法就介绍VAN了
总结一下:
-
加载图像可以使用BitmapFactory和Bitmap的相关方法。
-
Options参数很牛逼,要多多运用
-
如果要裁剪或者缩放图片,则只能使用Bitmap的Create系列函数
-
一定要注意,在加载或者创建Bitmap时,必须要使用try…catch语句捕捉OutOfMemoryError,防止出现OOM。
5、常用函数
(1)copy(Config config,boolean isMutable)
这个函数是根据源图像来创建一个副本,但可以指定副本的像素存储格式。它的两个参数含义为:
config表示存储格式
isMutable表示新创建的Bitmap是否可以更改其中元素。
诶~原来图像的像素还是可以被改变的吗?
其实是的,但是之前所学的加载和创建图片的方法不是每种弄出来的图像的像素都是可以改变的。
我们可以通过下面函数来判断图像像素是否可以更改。true表示可以,false表示不可以。
boolean isMutable();
如果图像的该函数返回了false,你还要用setPixel()等函数来更改,诶,就会报错。
通过BitmapFactory创建出来的Bitmap都是像素不可以更改的,只有通过Bitmap中的下面几个函数创建的Bitmap才是像素可更改的。
copy(Bitmap.Config config,boolean isMutable)
createBitmap(int width,int height,Bitmap.Config config)
createSCaledBitmap(Bitmap src,int dstWidth,int dstHeight,boolean filter)
createBitmap(DisplayMetrics display,int width,int height,Bitmap.Config config)
大家谨记,对于像素不可以更改的图像,是不能作为画布的,比如下面这个:
Bitmap bmp = BitmapFactory.decodeResources(getRescoures(),R.drawable.xxx);
Canvas canvas = new Canvas(bmp);
canvas.drawColor(Color.RED);
这个时候,因为Bitmap是由工厂创建出来的,所以像素不可以更改,所以这个时候不能作为画布,这样写就会报错。
(2)extractAlpha()
这个函数的作用是Bitmap中抽出Alpha值,生成一幅只含有Alpha值的图像。像素存储的格式是ALPHA_8,有两个构造函数。
分别是:
Bitmap extractAlpha()
Bitmap extractAlpha(Paint paint,int[] offsetXY)
第二个参数中的Paint是具有MaskFilter效果的Paint对象,一般使用BlurMaskFilter模糊效果。
第二个参数为BlurMaskFilter效果的偏移量。但其取值并不一定与最终BlurMaskFilter的模糊半径一致。它只是一个建议值。
(3)分配控件获取
获取Bitmap的分配空间有三个函数。
//API 19引入,获取Bitmap所分配的内存,API 19以上的机器都使用该函数获取
int getAllocationByteCount();
//获取Bitmap分配的内存,在API 12中引入,在12< API <19 则使用该函数
int getByteCount()
//获取每行所分配的内存大小。Bitmap所占内存 = getRowBytes() * bitmap.getHeight() 即所占内存等于每行所占内存乘以行数。
//这个在API 1中引入,所以API 12一下必须用这个函数
int getRowBytes()
所以一般情况下获取内存分配都是:
if(api > kitkat){
return getAllocationByteCount();
}
if(api > HONEYCOMB_MR1){
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
文末
很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,对此我整理了一些资料,需要的可以免费分享给大家
这里笔者分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司19年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。如有需要点击这里前往我的GitHub免费获取。
【视频教程】
天道酬勤,只要你想,大厂offer并不是遥不可及!希望本篇文章能为你带来帮助,如果有问题,请在评论区留言。
享给大家
这里笔者分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司19年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。如有需要点击这里前往我的GitHub免费获取。
[外链图片转存中…(img-oII0qOTf-1710827288845)]
[外链图片转存中…(img-wpKNAK4s-1710827288845)]
【视频教程】
[外链图片转存中…(img-7lmLzhnN-1710827288846)]
天道酬勤,只要你想,大厂offer并不是遥不可及!希望本篇文章能为你带来帮助,如果有问题,请在评论区留言。