0、写在前面
| density | 1 | 1.5 | 2 | 3 | 3.5 | 4 | 
| densityDpi | 160 | 240 | 320 | 480 | 560 | 640 | 
1、占了多大内存?
| 
 1 
2 
3 
4 
 | 
public final int getByteCount() {    // int result permits bitmaps up to 46,340 x 46,340    return getRowBytes() * getHeight();} | 
2、给我一张图我告诉你占多大内存
2.1 getByteCount
| 
 1 
2 
3 
4 
5 
6 
 | 
public final int getrowBytes() {   if (mRecycled) {          Log.w(TAG, "Called getRowBytes() on a recycle()‘d bitmap! This is undefined behavior!");   }   return nativeRowBytes(mFinalizer.mNativeBitmap);} | 
| 
 1 
2 
3 
4 
 | 
static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle)     return static_cast<jint>(bitmap->rowBytes());} | 
| 
 1 
2 
 | 
/** Return the number of bytes between subsequent rows of the bitmap. */size_t rowBytes() const { return fRowBytes; } | 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
 | 
size_t SkBitmap::ComputeRowBytes(Config c, int width) {    return SkColorTypeMinRowBytes(SkBitmapConfigToColorType(c), width);}SkImageInfo.hstatic int SkColorTypeBytesPerPixel(SkColorType ct) {   static const uint8_t gSize[] = {    0,  // Unknown    1,  // Alpha_8    2,  // RGB_565    2,  // ARGB_4444    4,  // RGBA_8888    4,  // BGRA_8888    1,  // kIndex_8  };  SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gSize) == (size_t)(kLastEnum_SkColorType + 1),                size_mismatch_with_SkColorType_enum);   SkASSERT((size_t)ct < SK_ARRAY_COUNT(gSize));   return gSize[ct];}static inline size_t SkColorTypeMinRowBytes(SkColorType ct, int width) {    return width * SkColorTypeBytesPerPixel(ct);} | 
2.2 Density
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
 | 
public static Bitmap decodeResourceStream(Resources res, TypedValue value,    InputStream is, Rect pad, Options opts) {//实际上,我们这里的opts是null的,所以在这里初始化。if (opts == null) {    opts = new Options();}if (opts.inDensity == 0 && value != null) {    final int density = value.density;    if (density == TypedValue.DENSITY_DEFAULT) {        opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;    } else if (density != TypedValue.DENSITY_NONE) {        opts.inDensity = density; //这里density的值如果对应资源目录为hdpi的话,就是240    }}if (opts.inTargetDensity == 0 && res != null) {//请注意,inTargetDensity就是当前的显示密度,比如三星s6时就是640    opts.inTargetDensity = res.getDisplayMetrics().densityDpi;}return decodeStream(is, pad, opts);} | 
| 
 1 
2 
3 
4 
5 
 | 
public Options() {   inDither = false;   inScaled = true;   inPremultiplied = true;} | 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
 | 
static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options) {......    if (env->GetBooleanField(options, gOptions_scaledFieldID)) {        const int density = env->GetIntField(options, gOptions_densityFieldID);//对应hdpi的时候,是240        const int targetDensity = env->GetIntField(options, gOptions_targetDensityFieldID);//三星s6的为640        const int screenDensity = env->GetIntField(options, gOptions_screenDensityFieldID);        if (density != 0 && targetDensity != 0 && density != screenDensity) {            scale = (float) targetDensity / density;        }    }}const bool willScale = scale != 1.0f;......SkBitmap decodingBitmap;if (!decoder->decode(stream, &decodingBitmap, prefColorType,decodeMode)) {   return nullObjectReturn("decoder->decode returned false");}//这里这个deodingBitmap就是解码出来的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);}if (willScale) {    const float sx = scaledWidth / float(decodingBitmap.width());    const float sy = scaledHeight / float(decodingBitmap.height());    // TODO: avoid copying when scaled size equals decodingBitmap size    SkColorType colorType = colorTypeForScaledOutput(decodingBitmap.colorType());    // FIXME: If the alphaType is kUnpremul and the image has alpha, the    // colors may not be correct, since Skia does not yet support drawing    // to/from unpremultiplied bitmaps.    outputBitmap->setInfo(SkImageInfo::Make(scaledWidth, scaledHeight,            colorType, decodingBitmap.alphaType()));    if (!outputBitmap->allocPixels(outputAllocator, NULL)) {        return nullObjectReturn("allocation failed for scaled bitmap");    }    // If outputBitmap‘s pixels are newly allocated by Java, there is no need    // to erase to 0, since the pixels were initialized to 0.    if (outputAllocator != &javaAllocator) {        outputBitmap->eraseColor(0);    }    SkPaint paint;    paint.setFilterLevel(SkPaint::kLow_FilterLevel);    SkCanvas canvas(*outputBitmap);    canvas.scale(sx, sy);    canvas.drawBitmap(decodingBitmap, 0.0f, 0.0f, &paint);}......} | 
2.3 精度
| 
 1 
2 
 | 
outputBitmap->setInfo(SkImageInfo::Make(scaledWidth, scaledHeight,            colorType, decodingBitmap.alphaType())); | 
| 
 1 
2 
3 
4 
 | 
if (willScale && decodeMode != SkImageDecoder::kDecodeBounds_Mode) {    scaledWidth = int(scaledWidth * scale + 0.5f);    scaledHeight = int(scaledHeight * scale + 0.5f);} | 
“源码之前,了无秘密”。
2.4 小结
3、想办法减少 Bitmap 内存占用
3.1 Jpg 和 Png
『啪!!!』『谁这么缺德!!打人不打脸好么!』
JPG 不适用于所含颜色很少、具有大块颜色相近的区域或亮度差异十分明显的较简单的图片。对于需要高保真的较复杂的图像,PNG 虽然能无损压缩,但图片文件较大。
3.2 使用 inSampleSize
| 
 1 
2 
3 
 | 
BitmapFactory.Options options = new Options();options.inSampleSize = 2;Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId, options); | 
3.3 使用矩阵
『基友』『是在下输了。。』
| 
 1 
2 
3 
4 
5 
 | 
Matrix matrix = new Matrix();matrix.preScale(2, 2, 0f, 0f);//如果使用直接替换矩阵的话,在Nexus6 5.1.1上必须关闭硬件加速canvas.concat(matrix);canvas.drawBitmap(bitmap, 0,0, paint); | 
| 
 1 
2 
3 
 | 
Matrix matrix = new Matrix();matrix.preScale(2, 2, 0, 0);canvas.drawBitmap(bitmap, matrix, paint); | 
| 
 1 
2 
3 
4 
5 
 | 
Matrix matrix = new Matrix();matrix.postScale(2, 2, 0, 0);imageView.setImageMatrix(matrix);imageView.setScaleType(ScaleType.MATRIX);imageView.setImageBitmap(bitmap); | 
3.4 合理选择Bitmap的像素格式
| 格式 | 描述 | 
| ALPHA_8 | 只有一个alpha通道 | 
| ARGB_4444 | 这个从API 13开始不建议使用,因为质量太差 | 
| ARGB_8888 | ARGB四个通道,每个通道8bit | 
| RGB_565 | 每个像素占2Byte,其中红色占5bit,绿色占6bit,蓝色占5bit | 
3.5 高能:索引位图(Indexed Bitmap)
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
 | 
public enum Config {    // these native values must match up with the enum in SkBitmap.h    ALPHA_8     (2),    RGB_565     (4),    ARGB_4444   (5),    ARGB_8888   (6);    final int nativeInt;} | 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
 | 
enum Config {   kNo_Config,   //!< bitmap has not been configured     kA8_Config,   //!< 8-bits per pixel, with only alpha specified (0 is transparent, 0xFF is opaque)   //看这里看这里!!↓↓↓↓↓    kIndex8_Config, //!< 8-bits per pixel, using SkColorTable to specify the colors      kRGB_565_Config, //!< 16-bits per pixel, (see SkColorPriv.h for packing)    kARGB_4444_Config, //!< 16-bits per pixel, (see SkColorPriv.h for packing)    kARGB_8888_Config, //!< 32-bits per pixel, (see SkColorPriv.h for packing)    kRLE_Index8_Config,    kConfigCount}; | 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
 | 
bool SkPNGImageDecoder::getBitmapColorType(png_structp png_ptr, png_infop info_ptr,                                       SkColorType* colorTypep,                                       bool* hasAlphap,                                       SkPMColor* SK_RESTRICT theTranspColorp) {png_uint_32 origWidth, origHeight;int bitDepth, colorType;png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,             &colorType, int_p_NULL, int_p_NULL, int_p_NULL);#ifdef PNG_sBIT_SUPPORTED  // check for sBIT chunk data, in case we should disable dithering because  // our data is not truely 8bits per component  png_color_8p sig_bit;  if (this->getDitherImage() && png_get_sBIT(png_ptr, info_ptr, &sig_bit)) {#if 0    SkDebugf("----- sBIT %d %d %d %d\n", sig_bit->red, sig_bit->green,             sig_bit->blue, sig_bit->alpha);#endif    // 0 seems to indicate no information available    if (pos_le(sig_bit->red, SK_R16_BITS) &&        pos_le(sig_bit->green, SK_G16_BITS) &&        pos_le(sig_bit->blue, SK_B16_BITS)) {        this->setDitherImage(false);    }}#endifif (colorType == PNG_COLOR_TYPE_PALETTE) {    bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr);    *colorTypep = this->getPrefColorType(kIndex_SrcDepth, paletteHasAlpha);    // now see if we can upscale to their requested colortype    //这段代码,如果返回false,那么colorType就被置为索引了,那么我们看看如何返回false    if (!canUpscalePaletteToConfig(*colorTypep, paletteHasAlpha)) {        *colorTypep = kIndex_8_SkColorType;    }} else {...... }return true;} | 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
 | 
static bool canUpscalePaletteToConfig(SkColorType dstColorType, bool srcHasAlpha) {  switch (dstColorType) {    case kN32_SkColorType:    case kARGB_4444_SkColorType:        return true;    case kRGB_565_SkColorType:        // only return true if the src is opaque (since 565 is opaque)        return !srcHasAlpha;    default:        return false;}} | 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
 | 
try {   Options options = new Options();   options.inPreferredConfig = Config.RGB_565;Bitmap bitmap = BitmapFactory.decodeStream(getResources().getAssets().open("index.png"), null, options);   Log.d(TAG, "bitmap.getConfig() = " + bitmap.getConfig());   Log.d(TAG, "scaled bitmap.getByteCount() = " + bitmap.getByteCount());   imageView.setImageBitmap(bitmap);} catch (IOException e) {    e.printStackTrace();} | 
| 
 1 
2 
 | 
D/MainActivity: bitmap.getConfig() = nullD/MainActivity: scaled bitmap.getByteCount() = 36864 | 
public final Bitmap.Config getConfig ()Added in API level 1If the bitmap’s internal config is in one of the public formats, return that config, otherwise return null.
3.6 不要辜负。。。『哦,不要姑父!』
『排期太紧了,这些给我出一系列图吧』『好,不过每张图都是 300*30 0的 png 哈,总共 5 张,为了适配不同的分辨率,需要出 xxhdpi 和 xxxhdpi 的两套图。。』
4、结语
Android 开发绕不过的坑:你的 Bitmap 究竟占多大内存?
原文:http://www.cnblogs.com/krislight1105/p/5203277.html