android图片:高效加载大图
2015-09-17 14:58
453 查看
图片有各种大小和形状,很多时候我们要显示的图片的分辨率大小远大于手机屏幕的分辨率,这时候我们通常是先对图片做压缩再加载到内存显示,因为一方面原图占用太多内存,容易导致OOM,另一方面,只要压缩适当,压缩后的图片在手机上的显示效果和原图没太大差别,手机分辨率就这么多,你原图分辨率再高,显示在手机屏幕上,也超不过其最大分辨率,视觉上看起来效果一样,占用的内存却大大不一样。
BitmapFactory提供了对图片操作的一系列方法,下面是对图片压缩的一个写法。
开始时将inJustDecodeBounds属性设置为true,避免为图片分配内存,但是却可以读取图片的大小,再通过这个大小计算出压缩倍数inSampleSize,之后再将inJustDecodeBounds属性设置为false,读取压缩后的图片,并为其分配内存。下面看一下计算inSampleSize的具体实现。
这里有两个问题:
1、 为什么要先把高宽除以2.
2、 为什么每次都是inSampleSize*2,也就是为什么inSampleSize的值是2的幂。
高宽除以2,是因为存在这么一种情况,原图高宽除以2之后,大小比要显示的高宽要小,这个时候如果inSampleSize*2的话,图片会有些失真。例如原图是100*100,而要显示的图的大小是80*80,如果设置inSampleSize为2,那么压缩后的图为50*50,50*50的图片显示在80*80的ImageView中,会有些失真,所以这个时候inSampleSize应该为1,将100*100的图片显示在80*80的ImageView中,就不会失真。
inSampleSize的值是2的幂,是因为解码器使用基于2的幂值, inSampleSize的其他任何值将被四舍五入到最近的2的幂(Note: thedecoder uses a final value based on powers of 2, any other value will berounded down to the nearest power of 2.)。所以我们这里直接就把inSampleSize处理为2的幂值。
当然,计算inSampleSize的方法可以根据实际情况来设置,例如你就是要把图片压缩的占用内存更小,不考虑失真,那么完全可以把inSampleSize设置为一个更大的值。
根据上面的方法,假设想在100*100的ImageView中显示图片,就可以这么写了:
BitmapFactory提供了对图片操作的一系列方法,下面是对图片压缩的一个写法。
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); }
开始时将inJustDecodeBounds属性设置为true,避免为图片分配内存,但是却可以读取图片的大小,再通过这个大小计算出压缩倍数inSampleSize,之后再将inJustDecodeBounds属性设置为false,读取压缩后的图片,并为其分配内存。下面看一下计算inSampleSize的具体实现。
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) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize; }
这里有两个问题:
1、 为什么要先把高宽除以2.
2、 为什么每次都是inSampleSize*2,也就是为什么inSampleSize的值是2的幂。
高宽除以2,是因为存在这么一种情况,原图高宽除以2之后,大小比要显示的高宽要小,这个时候如果inSampleSize*2的话,图片会有些失真。例如原图是100*100,而要显示的图的大小是80*80,如果设置inSampleSize为2,那么压缩后的图为50*50,50*50的图片显示在80*80的ImageView中,会有些失真,所以这个时候inSampleSize应该为1,将100*100的图片显示在80*80的ImageView中,就不会失真。
inSampleSize的值是2的幂,是因为解码器使用基于2的幂值, inSampleSize的其他任何值将被四舍五入到最近的2的幂(Note: thedecoder uses a final value based on powers of 2, any other value will berounded down to the nearest power of 2.)。所以我们这里直接就把inSampleSize处理为2的幂值。
当然,计算inSampleSize的方法可以根据实际情况来设置,例如你就是要把图片压缩的占用内存更小,不考虑失真,那么完全可以把inSampleSize设置为一个更大的值。
根据上面的方法,假设想在100*100的ImageView中显示图片,就可以这么写了:
mImageView.setImageBitmap( decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
相关文章推荐
- Android之SurfaceView
- Gradle 构建android程序
- android 单击和滚动效果调整
- Android通过泛型简化findViewById类型转换
- Android Annotations开源框架简介(一)
- Android Native 同步类
- Android 一些常用的但是记不住的设置
- android ProgressDialog 提示窗口 代码
- Android 上千张图片的列表滑动加载
- 实战操作ADB命令
- 轻松学习android百度地图开发(三)
- Android jni开发资料--NDK环境搭建
- Android软键盘弹出时把布局顶上去的解决方法
- android studio Gradle: 警告:编码 GBK 的不可映射字符的 ...
- Android 语音识别+语音搜索源码 Voice Search
- Android左右摇摆动画,开始动画,结束动画
- Android模块化编程之引用本地的aar
- android listview仿iphone弹簧特效
- Android选择本地图片或者照片裁剪
- Android Scroller类的详细分析