安卓图片优化

高效加载较大的 Bitmaps  


     图片有各种形状和各种大小,在很多情况下,图片的实际大小都比图片在应用中所显示的大小要大的多,比如Android系统自带的 Gallery  应用显示的照片实际的分辨率通常比手机设备的密度要高很多  


     考虑到我们是在开发一款内存使用受限的应用,理想的情况下,我们只是想把一个低分辨率版本的位图载入内存,一般来说这个低分辨率版本的位图要跟UI元件实际需要显示的大小相符。一张高分辨率的图片并不会给我们带来任何明显的好处,但却会占用宝贵的内存资源和产生额外的性能开销  


获取Bitmap的尺寸大小和类型  


     BitmapFactory 类为我们提供了几种decoding方法(decodeByteArray(), decodeFile(),decodeResource(), etc)来从不同的来源创建出 Bitmap ,如何选择最恰当的decode方法取决于你的图片数据来源,这些方法都会去尝试申请内存来构建Bitmap对象,所有很容易就会导致一个OutOfMemory  异常,每种类型的decode方法都有额外的签名来让你通过 BitmapFactory.Options 类来指定decoding选项,当我们decoding的时候把inJustDecodeBounds 属性设置为true 可以避免申请内存,虽然会返回一个null Bitmap对象 ,但是会为我们传入的BitmapFactory.Options  对象设置 outWidth, outHeight and outMimeType 等属性的值,这个技术可以让你在构建Bitmap对象之前事先知道它的大小和类型  


[java]  
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;   

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;  


为了避免java.lang.OutOfMemory  异常,在decoding Bitmap之前你有必要去检测Bitmap的大小和类型,除非你真的是非常清楚你要decoding的Bitmap的大小,还有这个大小要适合当前应用内存环境  


载入‘缩小版’的Bitmap到内存  


     现在我们已经知道了Bitmap的大小,这将有助于我们来决策是载入整张Bitmap还是载入’缩小版’的Bitmap,这里有一些因素需要进行考虑  


            一、载入整张图片预计要使用多少内存  
            二、在考虑到其它方面内存需要的情况下,你想把多少数量的内存给Bitmap使用  
            三、用于显示Bitmap的 ImageView 控件或其它UI元件的大小  
            四、当前设备屏幕的大小和密度  
      
例如,一点都不值得载入1024x768  像素的图片到内存中,而最终只在128x96 像素大小的 ImageView 控件上显示   
      
     我们应该告诉decoder,图像需要进行抽样,载入一个更小号的Bitmap到内存中,设置 BitmapFactory.Options 对象的 inSampleSize 属性为true 。例如,一张分辨率为2048x1536 像素的图片,如果decode的时候把inSampleSize   设置为4,那么得到的最终图片的大小大约为512x384 ,载入内存耗费0.75M而不是载入整张时的12M (假设位图的配置为 ARGB_8888) ,下面有一个在目标高和宽基础上计算inSampleSize 的方法  


[java]  
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;   
}   

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;  
}  
NOTE :  inSampleSize  值是2的幂的话,对于decoder来说会更快和更高效。然而,如果你想把调整过大小的位图缓存到内存或硬盘上时,依然非常有意义decoding最合适的位图大小,这样有助于节省内存或节省硬盘空间  


下面是一个获取位图的方法  
[java]  
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);   
}   

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);  
}  


这个方法可以很容易的做到在任意显示尺寸大小的UI元件中去载入一张位图  
[java]  
mImageView.setImageBitmap(   
    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));   

mImageView.setImageBitmap(  
    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值