在Android开发中,咱们不免会遇到加载图片的场景。不论是网络图片、资源图片或者是SD卡中的图片,都须要加载到内存中使用。若是不能合理处理图片,可能会致使OOM的问题或者其余性能问题,接下就讨论下Android中图片资源处理的几种经常使用的方式。android
在Android中开发的时候都会用到不少图片素材,对于某些背景图片、各类图标或者其余一些提示图片咱们一般会放到res目录中的drawable中。缓存
咱们知道在res目录下有不少drawable目录,好比:drawable、drawable-hdpi、drawable-mdpi等。这些目录对应了不一样密度的屏幕,在不一样密度的屏幕下会优先从对应目录下取图片资源。网络
目录名称 | 密度(Density) |
---|---|
res/drawable | 0 |
res/drawable-ldpi | 120 |
res/drawable-mdpi | 160 |
res/drawable-hdpi | 240 |
res/drawable-xhdpi | 320 |
res/drawable-xxdpi | 480 |
这六种目录表明了目前市面上Android机型不一样的6中密度的屏幕。框架
注意:res/drawable目录的密度为0,不是说有机型的屏幕密度为0。这是默认密度,在不一样机型下默认密度不同。ide
Android在加载资源图片时,会先获取当前设备的屏幕密度,而后根据屏幕密度去找图片资源。若是没有在对应的文件夹下找到图片资源,就会采起就近原则,从与屏幕密度最相近的图片资源目录获取。若是都没有就只能从默认的资源目录下获取(也就是res/drawable)。性能
在获取到图片资源时,若是密度不匹配,Android会对图片进行处理。好比在res/drawable-mdpi找到了图片,可是设备屏幕密度是xxdpi的,那么Android就会按照3倍大小缩放这张图片。根据图片内存的计算公式(图片高度 x 图片宽度 x 一个像素占用的内存大小)。好比:一张800x480的图片原来占用内存大约是1.46M,增长3倍后图片是3200x1920,占用内存大约是23M。而通常Android系统分配给每一个进程的内存也才一百多M,在低配手机中很容易就产生OOM。学习
针对上面的状况,如何处理资源文件呢?由于Android拿到低密度的图片时,在高密度设备会将其放大。因此在添加资源文件时,应该优先使用高品质图片从高密度的目录往下放。优化
Bitmap类型的图片也是在开发中常常用到的。对于Bitmap图片若是不加处理直接使用的话,也很容易致使OOM。由于会有一些占用很大的图片被加载到内存中,而真正的需求可能并不须要这么大的图片。spa
接下来的内容大多来自于Google推荐的一种处理Bitmap图片的方法。连接在下面,感兴趣的同窗也能够直接阅读文档。code
developer.android.com/topic/perfo…
在Google的方案中,主要的思想是按需加载Bitmap。所谓的按需加载,就是根据图片的尺寸和要加载图片的ImageView的尺寸对Bitmap进行压缩处理。
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
复制代码
上面的代码会获取到Bitmap图片的宽、高、MimeType。同时这里有个参数是比较重要的,inJustDecodeBounds这个参数设为true的时候不会在内存中分配Bitmap的空间,只是获取到了Bitmap图片的宽高等信息。
public static int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
//若是Bitmap图片宽高大于ImageView宽高,就缩放图片
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
//计算缩放比例
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
复制代码
上面的代码经过图片的尺寸计算Bitmap图片的缩放比例。最终获得的结果inSampleSize就是须要缩放的比例。
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
复制代码
这一步是获取获得最终的Bitmap图片,能够看到BitmapFactory.Options options的inSampleSize是缩放比例,在获取图片以前,将inJustDecodeBounds设置为false,而后再次调用decode方法就得到了最终的Bitma对象。
在处理图片时,特别是网络图片若是咱们想要高效的利用图片资源。这个时候使用图片加载框架是一个很好的选择。好比:Glide框架。这也是Google推荐的图片加载框架。
图片加载框架不只能帮助咱们处理图片。同时还能经过缓存复用图片,提升图片的利用率。
在Android开发中,图片的处理几乎是因此应用都要面对的场景,可以了解一些图片的优化的小技巧,可以提升咱们在开发中的效率与质量。若是各位同窗有更好的方法,欢迎在评论区讨论,你们共同窗习。