Android Bitmaps緩衝

來源:互聯網
上載者:User

標籤:

Android 開發中,bitmap是引起記憶體流失的罪魁禍首,關於bitmap的載入,緩衝策略,官方已經給了很詳細的方法:

緩衝之Memory Cache:

 

緩衝的策略,是利用應用程式的分配的記憶體拿出適當的一部分利用LruCache演算法進行緩衝。關於用多少記憶體來緩衝圖片,這個要根據不同的圖片,機型和 螢幕的解析度來進行綜合考量,比如對於同一個圖片,Galaxy Nexus 就比Nexus S需要的記憶體多。

以LruCache緩衝範例程式碼:

 

private LruCache<String, Bitmap> mMemoryCache;@Overrideprotected void onCreate(Bundle savedInstanceState) {    ...    // Get max available VM memory, exceeding this amount will throw an    // OutOfMemory exception. Stored in kilobytes as LruCache takes an    // int in its constructor.    final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);    // Use 1/8th of the available memory for this memory cache.    final int cacheSize = maxMemory / 8;    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {        @Override        protected int sizeOf(String key, Bitmap bitmap) {            // The cache size will be measured in kilobytes rather than            // number of items.            return bitmap.getByteCount() / 1024;        }    };    ...}public void addBitmapToMemoryCache(String key, Bitmap bitmap) {    if (getBitmapFromMemCache(key) == null) {        mMemoryCache.put(key, bitmap);    }}public Bitmap getBitmapFromMemCache(String key) {    return mMemoryCache.get(key);}

  

 

當載入圖片的時候,如果緩衝裡面有圖片,就直接從緩衝載入,否者就在一個background thread執行載入圖片的操作:

public void loadBitmap(int resId, ImageView imageView) {    final String imageKey = String.valueOf(resId);    final Bitmap bitmap = getBitmapFromMemCache(imageKey);    if (bitmap != null) {        mImageView.setImageBitmap(bitmap);    } else {        mImageView.setImageResource(R.drawable.image_placeholder);        BitmapWorkerTask task = new BitmapWorkerTask(mImageView);        task.execute(resId);    }}

  

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {    ...    // Decode image in background.    @Override    protected Bitmap doInBackground(Integer... params) {        final Bitmap bitmap = decodeSampledBitmapFromResource(                getResources(), params[0], 100, 100));        addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);        return bitmap;    }    ...}

  

緩衝之Disk Cache:

 

對於圖片比較小,圖片個數比較少的,已經對載入效率比較快的要求,用Memory Cache無疑是最好的選擇,但是當對於,圖片比較多的情境,比如,Gridview ,ListView載入大量的圖片,記憶體就吃不消了,這時候,就需要用到磁碟等外部存放裝置來進行緩衝。

實際上,如果對圖片切換比較頻繁的話,那麼 ContentProvider 絕壁是個好的選擇,比如 image gallery application.

 

關於使用Disk Cache的官方範例程式碼如下:

 

 

private DiskLruCache mDiskLruCache;private final Object mDiskCacheLock = new Object();private boolean mDiskCacheStarting = true;private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MBprivate static final String DISK_CACHE_SUBDIR = "thumbnails";@Overrideprotected void onCreate(Bundle savedInstanceState) {    ...    // Initialize memory cache    ...    // Initialize disk cache on background thread    File cacheDir = getDiskCacheDir(this, DISK_CACHE_SUBDIR);    new InitDiskCacheTask().execute(cacheDir);    ...}class InitDiskCacheTask extends AsyncTask<File, Void, Void> {    @Override    protected Void doInBackground(File... params) {        synchronized (mDiskCacheLock) {            File cacheDir = params[0];            mDiskLruCache = DiskLruCache.open(cacheDir, DISK_CACHE_SIZE);            mDiskCacheStarting = false; // Finished initialization            mDiskCacheLock.notifyAll(); // Wake any waiting threads        }        return null;    }}class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {    ...    // Decode image in background.    @Override    protected Bitmap doInBackground(Integer... params) {        final String imageKey = String.valueOf(params[0]);        // Check disk cache in background thread        Bitmap bitmap = getBitmapFromDiskCache(imageKey);        if (bitmap == null) { // Not found in disk cache            // Process as normal            final Bitmap bitmap = decodeSampledBitmapFromResource(                    getResources(), params[0], 100, 100));        }        // Add final bitmap to caches        addBitmapToCache(imageKey, bitmap);        return bitmap;    }    ...}public void addBitmapToCache(String key, Bitmap bitmap) {    // Add to memory cache as before    if (getBitmapFromMemCache(key) == null) {        mMemoryCache.put(key, bitmap);    }    // Also add to disk cache    synchronized (mDiskCacheLock) {        if (mDiskLruCache != null && mDiskLruCache.get(key) == null) {            mDiskLruCache.put(key, bitmap);        }    }}public Bitmap getBitmapFromDiskCache(String key) {    synchronized (mDiskCacheLock) {        // Wait while disk cache is started from background thread        while (mDiskCacheStarting) {            try {                mDiskCacheLock.wait();            } catch (InterruptedException e) {}        }        if (mDiskLruCache != null) {            return mDiskLruCache.get(key);        }    }    return null;}// Creates a unique subdirectory of the designated app cache directory. Tries to use external// but if not mounted, falls back on internal storage.public static File getDiskCacheDir(Context context, String uniqueName) {    // Check if media is mounted or storage is built-in, if so, try and use external cache dir    // otherwise use internal cache dir    final String cachePath =            Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||                    !isExternalStorageRemovable() ? getExternalCacheDir(context).getPath() :                            context.getCacheDir().getPath();    return new File(cachePath + File.separator + uniqueName);}

 

  

 

memory Cache 在UI線程中執行,Disk Cache則是在Backound thread 中執行。

當旋轉螢幕,或者其他配置改變的時候,比如電話進來,彈出對話方塊,對Activity進行銷毀,重設的時候,需要對之前緩衝進行儲存;

比如在一個Fragment中儲存緩衝對象的程式碼範例:

private LruCache<String, Bitmap> mMemoryCache;@Overrideprotected void onCreate(Bundle savedInstanceState) {    ...    RetainFragment retainFragment =            RetainFragment.findOrCreateRetainFragment(getFragmentManager());    mMemoryCache = retainFragment.mRetainedCache;    if (mMemoryCache == null) {        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {            ... // Initialize cache here as usual        }        retainFragment.mRetainedCache = mMemoryCache;    }    ...}class RetainFragment extends Fragment {    private static final String TAG = "RetainFragment";    public LruCache<String, Bitmap> mRetainedCache;    public RetainFragment() {}    public static RetainFragment findOrCreateRetainFragment(FragmentManager fm) {        RetainFragment fragment = (RetainFragment) fm.findFragmentByTag(TAG);        if (fragment == null) {            fragment = new RetainFragment();            fm.beginTransaction().add(fragment, TAG).commit();        }        return fragment;    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setRetainInstance(true);    }}

  

 

From :http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html#config-changes

 

Android Bitmaps緩衝

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.