Android进阶练习 - 高效显示Bitmap(高效加载较大的 Bitmaps)


高效加载较大的 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对象之前事先知道它的大小和类型

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 的方法

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最合适的位图大小,这样有助于节省内存或节省硬盘空间

下面是一个获取位图的方法
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元件中去载入一张位图
mImageView.setImageBitmap(
    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

在其他的 BitmapFactory.decode*    系列的decode方法中以上获取位图的技术也是需要的









你可能感兴趣的:(Android,Android)