Android大圖片處理

圖片緩存架構

BitMap創建方式

1.BitMapFactory.decodeResoure()  最消耗資源,因爲他會根據手機屏幕進行適配(慎用,比較消耗性能最大的)
//第一步
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;
            }
        }
        if (opts.inTargetDensity == 0 && res != null) {
            opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
        }

//第二步
bm = nativeDecodeAsset(asset, outPadding, opts);
2.BitMapFactory.decodeFile()(推薦,是通過調用native方式創建BitMap,消耗性能最少)
//Jni調用
 private static Bitmap decodeStreamInternal(InputStream is, Rect outPadding, Options opts) {
        // ASSERT(is != null);
        byte [] tempStorage = null;
        if (opts != null) tempStorage = opts.inTempStorage;
        if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
        return nativeDecodeStream(is, tempStorage, outPadding, opts);
    }
3.BitMapFactory.decodeByteArray()(推薦,是通過調用native方式創建BitMap,消耗性能最少)
 public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
        if ((offset | length) < 0 || data.length < offset + length) {
            throw new ArrayIndexOutOfBoundsException();
        }

        Bitmap bm;

        Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeBitmap");
        try {
            bm = nativeDecodeByteArray(data, offset, length, opts);

            if (bm == null && opts != null && opts.inBitmap != null) {
                throw new IllegalArgumentException("Problem decoding into existing bitmap");
            }
            setDensityFromOptions(bm, opts);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
        }

        return bm;
    }

BitMap創建與優化

1.BitmapFactory.decodeFile()
2.BitmapFactory.Options options= new BitmapFactory.Options();
options.inPreferredConfig配置

這裏寫圖片描述

BitMap大圖片的處理

1.
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;

2.如果我們有個圖片是1024*768的圖片顯示在128*60的ImageView是毫無意義的,那麼我們應該如何出處理呢?谷歌官方壓縮的算法處理如下:

//計算出最優的壓縮值
//參數1 :Options對象 參數2:請求的寬(ImageView的寬度) 參數3:請求的高度(ImageView的高度)
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) {
        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;
}

3.真正的使用

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
    //如果自己手動設置壓縮比,最好是設置爲2的倍數,如果壓縮比是2,那麼圖片壓縮成1/4
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

Android開發文檔地址
https://developer.android.com/training/displaying-bitmaps/load-bitmap.html

BitMap各個版本的實現機制

  • 內存資源回收: Android 2.3(API Level 10)- 由於存儲圖像數據的Buffer分配在Native內存中, 並且只能通過 recycle( ) 來顯式釋放Buffer , 而3.0+中,該Buffer則分配在Dalvik Heap中, 因此 recycle( ) 通常當成兼容向下版本的調用. p.s. 該Buffer可在Android源碼Bitmap.java中找到.

  • 內存重利用: 3.0+允許開發者將已存在的Bitmap.Buffer分配給新的Bitmap來使用, 不過Bitmap之間的大小要嚴格相同, 而4.4(API Level 19)+則改變這一狀況.

*BitmapFactory.Options: 詳見SDK API Reference.

擴展閱讀

  • 上述都只是針對單個Bitmap的內存管理, 但是在開發中, 難免會需要管理大量的Bitmap, 那應該怎麼辦?

  • 在API Level 12中, 可以通過LruCache來緩存大量的內存Bitmap. 除此之外, 在Android源碼中, 可以找到, 一個名爲DiskLruCache的類, 它可以文件形式緩存Bitmap.

LruCache和DiskLruCache類可以參考
http://blog.csdn.net/hello_word1024/article/details/51638770
中貼出的地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章