android bitmap缓存机制(上)
2015-03-02 00:06
120 查看
android bitmap缓存机制,网上有很多译文http://my.oschina.net/ryanhoo/blog/88153,都是大同小异,我是直接看的译文,然后根据自己的理解,把文章的结构给大家再说明一下
图片加载,首先要解决的问题是图片太大,但是我有时候需要显示的尺寸又不必太大的时候,避免浪费内存的问题
解决方法是,首先获取图片的尺寸,而不是真正的把它加入内存,根据尺寸判断是否需要加载
BitmapFactory提供了几种解码方式(decodeByteArray(), decodeFile(), decodeResource()等等),以便从多种资源中创建一个Bitmap(位图)对象。可以根据你的图片数据来源选择最合适的解码方式。这些方法视图为构造Bitmap对象分配内存,因此很容易导致OutOfMemory(OOM)异常。每一种解码方式都有额外的特征,你可以通过BitmapFactory.Options类指定解码方法。在解码图片的时候设置inJustDecodeBounds属性为true,可以避免内存分配,返回的bitmap对象为null却可以设置outWidth,
outHeight和outMimeType。这项技术允许你在创建Bitmap(并分配内存)之前读取图片的尺寸和类型。
例如,如果最终只是要在ImageView中显示一张128*96px大小的缩略图,直接加载1024*768px的图片是非常不值得的。
为了告诉解码器如何对图像进行采样,加载更小版本的图片,需要在BitmapFactory.Options对象中将inSampleSize设置为true。例如,一张分辨率为2048*1536px的图像使用inSampleSize值为4的设置来解码,产生的Bitmap大小约为512*384px。相较于完整图片占用12M的内存,这种方式只需0.75M内存(假设Bitmap配置为ARGB_8888)。这里有一个方法用来计算基于目标高宽的sample size的值:
提示:使用2的次幂来设置inSampleSize值可以使解码器执行地更加迅速、更加高效。但是,如果你想在内存或者硬盘上缓存一个调整过大小的图片,通常还是解码到合适的图片尺寸更加节省空间。
要使用这个方法,首先要使用inJustDecodeBounds为true来解码尺寸信息,将options传递过去使用新的inSampleSize值再次解码并且要将inJustDecodeBounds值设置为false。
下面再来解决异步加载问题
解决方法是使用asycntask异步加载
解决方法是,我们再加载图片时候,把图片的resourceId记录在asycntask的属性里面,并且把imageview跟这个asycntask联系起来,那么可以说一个imageview就对应一个asycntask,通过imageview,我们是可以获得替它加载图片的asycntask的
OK,接着如果我们又有一个asycntask来替这个imageview加载图片,那么我们可以判断这个asycntask的resourceId是否跟原来的一样,如果一样,就不加载了,并且把这个asycntask给cancel()掉
而asycntask跟imageview联系的桥梁,译文里面使用了一个
上面就是具体思想,具体代码大家可以看译文
图片加载,首先要解决的问题是图片太大,但是我有时候需要显示的尺寸又不必太大的时候,避免浪费内存的问题
解决方法是,首先获取图片的尺寸,而不是真正的把它加入内存,根据尺寸判断是否需要加载
BitmapFactory提供了几种解码方式(decodeByteArray(), decodeFile(), decodeResource()等等),以便从多种资源中创建一个Bitmap(位图)对象。可以根据你的图片数据来源选择最合适的解码方式。这些方法视图为构造Bitmap对象分配内存,因此很容易导致OutOfMemory(OOM)异常。每一种解码方式都有额外的特征,你可以通过BitmapFactory.Options类指定解码方法。在解码图片的时候设置inJustDecodeBounds属性为true,可以避免内存分配,返回的bitmap对象为null却可以设置outWidth,
outHeight和outMimeType。这项技术允许你在创建Bitmap(并分配内存)之前读取图片的尺寸和类型。
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;接着就是把大图片变小,显示我们需要的尺寸
例如,如果最终只是要在ImageView中显示一张128*96px大小的缩略图,直接加载1024*768px的图片是非常不值得的。
为了告诉解码器如何对图像进行采样,加载更小版本的图片,需要在BitmapFactory.Options对象中将inSampleSize设置为true。例如,一张分辨率为2048*1536px的图像使用inSampleSize值为4的设置来解码,产生的Bitmap大小约为512*384px。相较于完整图片占用12M的内存,这种方式只需0.75M内存(假设Bitmap配置为ARGB_8888)。这里有一个方法用来计算基于目标高宽的sample size的值:
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) { if (width > height) { inSampleSize = Math.round((float)height / (float)reqHeight); } else { inSampleSize = Math.round((float)width / (float)reqWidth); } } return inSampleSize; }
提示:使用2的次幂来设置inSampleSize值可以使解码器执行地更加迅速、更加高效。但是,如果你想在内存或者硬盘上缓存一个调整过大小的图片,通常还是解码到合适的图片尺寸更加节省空间。
要使用这个方法,首先要使用inJustDecodeBounds为true来解码尺寸信息,将options传递过去使用新的inSampleSize值再次解码并且要将inJustDecodeBounds值设置为false。
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 options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); }
下面再来解决异步加载问题
解决方法是使用asycntask异步加载
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { private final WeakReference<ImageView> imageViewReference; private int data = 0; public BitmapWorkerTask(ImageView imageView) { // Use a WeakReference to ensure the ImageView can be garbage collected imageViewReference = new WeakReference<ImageView>(imageView); } // Decode image in background. @Override protected Bitmap doInBackground(Integer... params) { data = params[0]; return decodeSampledBitmapFromResource(getResources(), data, 100, 100)); } // Once complete, see if ImageView is still around and set bitmap. @Override protected void onPostExecute(Bitmap bitmap) { if (imageViewReference != null && bitmap != null) { final ImageView imageView = imageViewReference.get(); if (imageView != null) { imageView.setImageBitmap(bitmap); } } } }然后是解决多线程的问题,因为如果在来回滑动时,可能会造成有两个asycntask同时在加载同一张图片,这样就造成了浪费
解决方法是,我们再加载图片时候,把图片的resourceId记录在asycntask的属性里面,并且把imageview跟这个asycntask联系起来,那么可以说一个imageview就对应一个asycntask,通过imageview,我们是可以获得替它加载图片的asycntask的
OK,接着如果我们又有一个asycntask来替这个imageview加载图片,那么我们可以判断这个asycntask的resourceId是否跟原来的一样,如果一样,就不加载了,并且把这个asycntask给cancel()掉
而asycntask跟imageview联系的桥梁,译文里面使用了一个
AsyncDrawable类
上面就是具体思想,具体代码大家可以看译文
相关文章推荐
- android bitmap缓存机制(下)
- Android客户端中Bitmap的下载过程和缓存机制
- Android Bitmap大量使用不产生OOM之使用缓存机制
- Android平台Bitmap缓存为文件
- Android客户端缓存机制(文字缓存跟多媒体文件缓存)
- android bitmap 缓存实现(OOM)
- Android客户端缓存机制(文字缓存和多媒体文件缓存)
- Android之ListView异步加载网络图片(优化缓存机制)
- Android WebView缓存机制详解
- Android 中加载网络资源时的优化 缓存和异步机制
- Android 中加载网络资源时的优化 缓存和异步机制
- android 缓存Bitmap - 开发文档翻译
- Android-避免出现bitmap内存限制OUT OF MEMORY的一种方法-缓存
- android 缓存Bitmap - 开发文档翻译
- Android进阶练习 - 高效显示Bitmap(缓存 Bitmaps)
- Android之ListView异步加载网络图片(优化缓存机制)
- 【Android Training - 09】高效地显示Bitmap图片 [ Lesson 3 - 两种缓存Bitmap的方式 ]
- Android 利用缓存机制实现文件下载
- Android webView缓存机制
- Android之ListView异步加载网络图片(优化缓存机制)