天天看點

Android如何最優化的讀取一張Bitmap

Drawable緩存問題,顯示清晰度,

Resource.getDrawable會根據ID傳回Drawable,然後把這個Drawable緩存起來,看以下這個代碼段:

InputStream is = mAssets.openNonAsset(
                                value.assetCookie, file, AssetManager.ACCESS_STREAMING);
        //                System.out.println("Opened file " + file + ": " + is);
                        dr = Drawable.createFromResourceStream(this, value, is,
                                file, null);
                        is.close();
           
dr.setChangingConfigurations(value.changingConfigurations);
            cs = dr.getConstantState();
            if (cs != null) {
                if (mPreloading) {
                    sPreloadedDrawables.put(key, cs);
                } else {
                    synchronized (mTmpValue) {
                        //Log.i(TAG, "Saving cached drawable @ #" +
                        //        Integer.toHexString(key.intValue())
                        //        + " in " + this + ": " + cs);
                        mDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
                    }
                }
            }
           

緩存機制設計的很好,使用了弱引用機制避免記憶體溢出。但這個方法比較老實,如果資源是一張Bitmap的話,原圖是多大,它就會生成多大的。為了讓程式在不同的螢幕上面都比較清晰,并且圖檔占用記憶體不會過大,通常會根據不同的螢幕選擇加載不同的圖,但這樣包大小又上去了,一般,我們會用到這樣一個解決辦法:

隻放一張最大清晰度的圖,程式運作時根據目前螢幕尺寸對圖檔進行縮放。

這個辦法有一個缺點,就是加載時會先加載一張大圖,再根據大圖去生成小圖,記憶體峰值是兩張圖,在記憶體緊張的手機上有什麼辦法麼?下面是解決方案:

private BitmapDrawable getDrawable(int id) {
		int width = AppTools.getSreenSize(this, true);
		int height = AppTools.getSreenSize(this, false);
		BitmapFactory.Options opts = new BitmapFactory.Options();
		opts.inJustDecodeBounds = true;
		BitmapFactory.decodeResource(getResources(), id, opts);
		opts.inSampleSize = AppTools.computeSampleSize(opts, -1,
				(int) (width * height));
		opts.inJustDecodeBounds = false;
		Bitmap bitmap = null;
		try {
			bitmap = BitmapFactory.decodeResource(getResources(), id, opts);
		} catch (OutOfMemoryError e) {
		}
		if (bitmap == null) {
			return null;
		}
		return new BitmapDrawable(bitmap);

	}
           

先使用擷取圖檔的寬高,然後根據目标寬高計算出采樣大小,最後再真正讀取圖檔。

BitmapFactory.Options opts = new BitmapFactory.Options();
		opts.inJustDecodeBounds = true;
		BitmapFactory.decodeResource(getResources(), id, opts);