1.非本地资源Bitmap内存的计算
首先是一个像素占用的内存
- ARGB_8888: 每个像素4字节. 共32位,默认设置。
- Alpha_8: 只保存透明度,共8位,1字节。
- ARGB_4444: 共16位,2字节。
- RGB_565:共16位,2字节,只存储RGB值。
不考虑采样率压缩,加载一张bitmap占用内存
memory = width*height*一个像素占的字节
当我们设置BitmapFactory.options.inSampleSize采样率时,宽和高都会相应的改变,那么加载一张bitmap的内存
memory = width/inSampleSize*height/inSampleSize*一个像素占的字节
所以我们在一般处理bitmap的时候,经常从options.inPreferredConfig和options.inSampleSize进行内存的优化。
2.APK本地资源Bitmap内存的计算
当使用本地资源的时候,还需要考虑Density的影响。对于本地资源在代码或xml中使用时,最终会进行BitmapFactory.decodeResource()得到bitmap,这时就会牵涉到当前的屏幕Density和资源drawable所在Density。
BitmapFactory.java
public static Bitmap decodeResourceStream(Resources res, TypedValue value,InputStream is, Rect pad, Options opts) {
...
if (opts.inDensity == 0 && value != null) {
final int density = value.density;
if (density == TypedValue.DENSITY_DEFAULT) {
//inDensity默认为图片所在文件夹对应的密度
opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
} else if (density != TypedValue.DENSITY_NONE) {
opts.inDensity = density;
}
}
if (opts.inTargetDensity == 0 && res != null) {
//inTargetDensity为当前手机系统密度。
opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
}
return decodeStream(is, pad, opts);
}
BitmapFactory.cpp
static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options) {
//初始缩放系数
float scale = 1.0f;
if (env->GetBooleanField(options, gOptions_scaledFieldID)) {
const int density = env->GetIntField(options, gOptions_densityFieldID);
const int targetDensity = env->GetIntField(options, gOptions_targetDensityFieldID);
const int screenDensity = env->GetIntField(options, gOptions_screenDensityFieldID);
if (density != 0 && targetDensity != 0 && density != screenDensity) {
//缩放系数是当前系数密度/图片所在文件夹对应的密度;
scale = (float) targetDensity / density;
}
}
...
//原始解码出来的Bitmap的宽高;
int scaledWidth = decodingBitmap.width();
int scaledHeight = decodingBitmap.height();
//要使用缩放系数进行缩放,缩放后的宽高;
if (willScale && decodeMode != SkImageDecoder::kDecodeBounds_Mode) {
scaledWidth = int(scaledWidth * scale + 0.5f);
scaledHeight = int(scaledHeight * scale + 0.5f);
}
const float sx = scaledWidth / float(decodingBitmap.width());
const float sy = scaledHeight / float(decodingBitmap.height());
canvas.scale(sx, sy);
canvas.drawARGB(0x00, 0x00, 0x00, 0x00);
canvas.drawBitmap(decodingBitmap, 0.0f, 0.0f, &paint);
// now create the java bitmap
return GraphicsJNI::createBitmap(env, javaAllocator.getStorageObjAndReset(),
bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1);
}
可以看到使用本地资源drawable时的bitmap内存占用,mTargetDensity->手机系统分辨率,density ->drawable所在文件夹分辨率
memory = width/(mTargetDensity/inDensity )*height/(mTargetDensity/inDensity )*一个像素占的字节
由此看出,在平时UI切图的时候,尽量给大分辨率的图片,同时一定要放到对应的文件夹中去。
结语
如有不同见解请留言探讨
网友评论