android bitmap缓存机制(下)
来源:互联网 发布:qq视频录像软件注册码 编辑:程序博客网 时间:2024/04/30 11:36
上篇文章说明了图片的加载时,要注意大小问题,和并发的处理问题
下面我们再说明一下bitmap的缓存机制
缓存有两种,一种是内存缓存,较快,但是大小有限
一种是硬盘缓存,较慢,但是空间较大
内存缓存主要是使用一个LruCache类,它可以存储一个键值对,也就是存储图片id和图片的bitmap对象
LruCache<String, Bitmap>
基本原理就是每次加载图片前,先判断是否在LruCache里面缓存了图片,有直接拿出来,没有再去加载,把加载后的图片缓存到LruCache里面用于下次的使用
private LruCache<String, Bitmap> mMemoryCache; @Overrideprotected void onCreate(Bundle savedInstanceState) { ... // Get memory class of this device, exceeding this amount will throw an // OutOfMemory exception. final int memClass = ((ActivityManager) context.getSystemService( Context.ACTIVITY_SERVICE)).getMemoryClass(); // Use 1/8th of the available memory for this memory cache. final int cacheSize = 1024 * 1024 * memClass / 8; mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { // The cache size will be measured in bytes rather than number of items. return bitmap.getByteCount(); } }; ...} public void addBitmapToMemoryCache(String key, Bitmap bitmap) { if (getBitmapFromMemCache(key) == null) { mMemoryCache.put(key, bitmap); }} public Bitmap getBitmapFromMemCache(String key) { return mMemoryCache.get(key);}
硬盘缓存使用的是DIskLruCache类,这是google推荐的一个类,其实本质也是跟内存缓存一样
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);}
OK,缓存机制就是上面,下面再讨论一个问题,就是配置更改的处理,例如activity的重建,或者横屏,这时会重新加载图片,造成浪费,我们可以把这些图片给缓存起来
保留原来缓存的方法是:可以通过使用Fragment传递到信的Activity(活动)实例,这个Fragment可以调用setRetainInstance(true)方法保留下来。在Activity(活动)被重新创建后,你可以在上面的Fragment中访问到已经存在的缓存对象,使得图片能快加载并重新填充到ImageView对象中。
private LruCache<String, Bitmap> mMemoryCache; @Overrideprotected void onCreate(Bundle savedInstanceState) { ... RetainFragment mRetainFragment = RetainFragment.findOrCreateRetainFragment(getFragmentManager()); mMemoryCache = RetainFragment.mRetainedCache; if (mMemoryCache == null) { mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { ... // Initialize cache here as usual } mRetainFragment.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(); } return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); }}
最后我们再来谈论一下viepager,gridview
滑动浏览模式(Swipe View Pattern)是一种很好的浏览详细图片的方式。你可以使用ViewPager组件配合PagerAdapter(适配器)来实现这种模式。然而,更加合适的适配器是FragmentStatePagerAdapter,它可以在ViewPager退出屏幕的时候自动销毁并存储Fragments的状态,使得内存依然保留下来。
注意:如果你只有少量的图片,并且确信它们不会超出程序的内存限制,使用常规的PagerAdapter或者FragmentPagerAdapter或许更加合适。
public class ImageDetailActivity extends FragmentActivity { public static final String EXTRA_IMAGE = "extra_image"; private ImagePagerAdapter mAdapter; private ViewPager mPager; // A static dataset to back the ViewPager adapter public final static Integer[] imageResIds = new Integer[] { R.drawable.sample_image_1, R.drawable.sample_image_2, R.drawable.sample_image_3, R.drawable.sample_image_4, R.drawable.sample_image_5, R.drawable.sample_image_6, R.drawable.sample_image_7, R.drawable.sample_image_8, R.drawable.sample_image_9}; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.image_detail_pager); // Contains just a ViewPager mAdapter = new ImagePagerAdapter(getSupportFragmentManager(), imageResIds.length); mPager = (ViewPager) findViewById(R.id.pager); mPager.setAdapter(mAdapter); } public static class ImagePagerAdapter extends FragmentStatePagerAdapter { private final int mSize; public ImagePagerAdapter(FragmentManager fm, int size) { super(fm); mSize = size; } @Override public int getCount() { return mSize; } @Override public Fragment getItem(int position) { return ImageDetailFragment.newInstance(position); } }}
public class ImageDetailFragment extends Fragment { private static final String IMAGE_DATA_EXTRA = "resId"; private int mImageNum; private ImageView mImageView; static ImageDetailFragment newInstance(int imageNum) { final ImageDetailFragment f = new ImageDetailFragment(); final Bundle args = new Bundle(); args.putInt(IMAGE_DATA_EXTRA, imageNum); f.setArguments(args); return f; } // Empty constructor, required as per Fragment docs public ImageDetailFragment() {} @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mImageNum = getArguments() != null ? getArguments().getInt(IMAGE_DATA_EXTRA) : -1; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // image_detail_fragment.xml contains just an ImageView final View v = inflater.inflate(R.layout.image_detail_fragment, container, false); mImageView = (ImageView) v.findViewById(R.id.imageView); return v; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); final int resId = ImageDetailActivity.imageResIds[mImageNum]; mImageView.setImageResource(resId); // Load image into ImageView }}
- android bitmap缓存机制(下)
- android bitmap缓存机制(上)
- Bitmap缓存机制
- android 缓存Bitmap
- android 缓存Bitmap
- Android Bitmap 缓存
- android缓存Bitmap
- Android Bitmap 缓存策略
- Android 缓存大量 bitmap
- android bitmap 缓存 处理
- android bitmap 怎么使用缓存?
- android bitmap 缓存工具类
- android: 缓存异步加载Bitmap
- Android中Bitmap缓存池
- Android bitmap 的缓存-LruCache
- android bitmap图片下载三级缓存
- Android中缓存Bitmap图像
- Android Bitmap大量使用不产生OOM之使用缓存机制
- IDR机制
- Eclipse 操作Hbase 代码一
- 读《烽烟中的敏捷》有感
- 【LeetCode从零单排】No83 Remove Duplicates from Sorted List
- fgets()学习
- android bitmap缓存机制(下)
- JAVA技术路线图
- Request的getParameter和getAttribute方法的区别
- DBus 入门与应用 -- DBus 的 C 编程接口
- IDR--Integer ID Management
- ubuntu14.04交叉编译vlc2.1.5源码,编译出在win32下运行的程序
- word2vec
- vi/vim 快捷键
- MVC