zoukankan      html  css  js  c++  java
  • Android Bitmaps缓存

    Android 开发中,bitmap是引起内存泄漏的罪魁祸首,关于bitmap的加载,缓存策略,官方已经给了很详细的方法:

    缓存之Memory Cache:

    缓存的策略,是利用应用程序的分配的内存拿出适当的一部分利用LruCache算法进行缓存。关于用多少内存来缓存图片,这个要根据不同的图片,机型和 屏幕的分辨率来进行综合考量,比如对于同一个图片,Galaxy Nexus 就比Nexus S需要的内存多。

    以LruCache缓存示例代码:

    private LruCache<String, Bitmap> mMemoryCache;
    
    @Override
    protected 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; // 10MB
    private static final String DISK_CACHE_SUBDIR = "thumbnails";
    
    @Override
    protected 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;
    
    @Override
    protected 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

  • 相关阅读:
    对TCP/IP协议的一些看法(12):UDP协议
    对TCP/IP协议的一些看法(11):窗口
    对TCP/IP协议的一些看法(10):TCP协议(2)
    对TCP/IP协议的一些看法(9):TCP协议(1)
    对TCP/IP协议的一些看法(8):DNS协议
    对TCP/IP协议的一些看法(7):传输层
    [BFS]翻币问题
    [BFS]骑士旅行
    [BFS]电子老鼠闯迷宫
    [BFS]P1434 [SHOI2002]滑雪
  • 原文地址:https://www.cnblogs.com/spring87/p/4913362.html
Copyright © 2011-2022 走看看