Android中图片资源非常的耗内存,当图片超过一定大小时就会出现OOM(Out Of Memory)异常。关于图片的加载优化,主要有采样压缩、缓存策略、异步加载等。
1. Bitmap加载方式
Bitmap有四种加载方式:
- BitmapFactory.decodeStream():以文件流方式
- BitmapFactory.decodeResource():以资源ID方式
- BitmapFactory.decodeFile():以文件路径方式
- BitmapFactory.decodeByteArray():以字节数组方式
- 以文件流方式加载
//图片在sdcard中
String filePath = "/sdcard/pic/test.png";
FileInputStream in = null;
try {
in = new FileInputStream(filePath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Bitmap bitmap = BitmapFactory.decodeStream(in);
//图片在Assets目录
String fileName = "sample.png";
InputStream in = getResources().getAssets().open(fileName);
Bitmap bitmap = BitmapFactory.decodeStream(in);
//图片在src目录
String filePath = "com/example/bitmap/test.png";
InputStream in = getClassLoader().getResourceAsStream(path);
Bitmap imageBitmap3 = BitmapFactory.decodeStream(in);
- 以资源ID方式加载
Bitmap bitmap =BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground);
//不推荐使用getDrawable()方式,该方法已经过时了
BitmapDrawable bitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.ic_launcher_foreground);
Bitmap bitmap = bitmapDrawable.getBitmap();
- 以文件路径方式加载
// 方法1
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);
//方法2:效率更高
FileInputStream fis = new FileInputStream(filePath);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(fis.getFD(), null, options);
- 以字节数组方式加载
byte[] data = new byte[1024];
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length, options);
2. Bitmap常用参数
BitmapFactory.Options参数主要有:
- inJustDecodeBounds :值为true,不返回bitmap,不分配内存,只返回bitmap的尺寸
- outWidth & outHeight :获取获取图片的宽度、高度
- inSampleSize :图片缩放的倍数,值为1表示不压缩
- inDensity :位图的像素压缩比
Bitmap.Config inPreferredConfig中的变量位数越高代表其可以存储的颜色信息越多,图像越逼真,选项有:
- ALPHA_8 :8位位图,每个像素占1个字节内存,它不存储颜色信息
- RGB_565 :16位位图,每个像素占2个字节内存,并且仅对RGB通道进行编码:红色存储5位精度,绿色存储6位精度,蓝色存储5位精度
- ARGB_4444 :16位位图,每个像素占2个字节内存,三个RGB颜色通道和alpha通道以4位精度存储(已经过时)
- ARGB_8888 :32位位图,每个像素占4个字节内存,每个通道以8位精度存储
- RGBA_F16 :64位位图,每个像素占8个字节内存,每个通道都存储为半精度浮点值
- HARDWARE :当需要在屏幕绘制位图时,最好选择此选项
示例代码如下:
@RequiresApi(api = Build.VERSION_CODES.O)
public static Bitmap decodeBitmapFromResource(String filePath, int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
//不返回bitmap,只返回这个bitmap的尺寸
options.inJustDecodeBounds = true;
//图片存储像素
options.inPreferredConfig = Bitmap.Config.RGBA_F16;
//预加载
BitmapFactory.decodeFile(filePath, options);
//计算出缩放比inSampleSize,只能是2的整数次幂
options.inSampleSize = getSampleSize(options, reqWidth, reqHeight);
//返回bitmap
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(filePath, options);
}
public static int getSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqHeight) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize >= reqHeight) && (halfWidth / inSampleSize >= reqWidth)) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
3. Bitmap缓存策略
- android LruCache:内存缓存,读取速度最快。内部采用LinkedHashMap进行实现
- android DiskLruCache:硬盘缓存或文件缓存,读取速度比内存缓存稍慢
- 网络缓存,利用第三方插件进行,读取速度最慢
- SQLite数据库保存或SharedPreferences保存
Android中关于几种常用的图片加载库的使用可查看:Android中几种常用图片加载库的使用