2 Loading Large Bitmaps Efficiently(高效加载大尺寸位图)

Images come in all shapes and sizes. In many cases they are larger than required for a typical application user interface (UI). 

图像在所有的图形和尺寸里。在一些例子中它们比一个典型应用的用户界面还要大。

For example, the system Gallery application displays photos taken using your Android devices's camera which are typically much higher resolution than the screen density of your device.

例如,系统图库应用显示你的android设备的照相机拍的照片通常是比你的手机屏幕密度更高的分辨率

Given that you are working with limited memory, ideally you only want to load a lower resolution version in memory.

考虑你在有限的内存工作,最好(理想状态)你只想读取低分辨率版本在内存。

The lower resolution version should match the size of the UI component that displays it.

低分辨率版本应该匹配同等大小的UI控件显示它。

An image with a higher resolution does not provide any visible benefit, but still takes up precious memory and incurs additional performance overhead due to additional on the fly scaling.

一个高分辨率的图像不能提供任何显示好处,而且占用宝贵的内存和由于不必要的缩放导致额外的性能开销。

This lesson walks you through decoding large bitmaps without exceeding the per application memory limit by loading a smaller subsampled version in memory.

这节课让你明白使用加载一个较小下采样版本在内存里来解码较大的位图不超出每个应用内存限制。

Read Bitmap Dimensions and Type(读取位图的尺寸和类型)

The BitmapFactory class provides several decoding methods (decodeByteArray()decodeFile(),decodeResource(), etc.) for creating a Bitmap from various sources.

BitmapFactory类提供一些解码的方法:

decodeByteArray(byte[]data,int offset,intlength,BitmapFactory.options opts);

decodeFile(String pathName,BitmapFactory.options opts);

decodeResource(Resources res,intid,BitmapFactory.options opts);

各种来源创建一个位图的。

Choose the most appropriate decode method based on your image data source.

位图选择适当的解码方法根据你的图像数据来源。

These methods attempt to allocate memory for the constructed bitmap and therefore can easily result in an OutOfMemory exception.

这些方法试图分配内存用于创建位图,所以更容易导致内存溢出的异常。

Each type of decode method has additional signatures that let you specify decoding options via the BitmapFactory.Options class.

每一种方法都附加通过BitmapFactory.Options类说明解码选项的特征。

Setting the inJustDecodeBounds property to true while decoding avoids memory allocation, returning null for the bitmap object but setting outWidthoutHeight and outMimeType.

避免解码时内存分配可以设置inJustDecodeBounds属性为true,返回空或者位图对象但是要设置

outWidth

outHeight

outMimeType

This technique allows you to read the dimensions and type of the image data prior to construction (and memory allocation) of the bitmap.

这个技巧允许你在创建位图(分配内存)前读取尺寸和图像数据。

[java]  view plain copy
  1. BitmapFactory.Options options = new BitmapFactory.Options();  
  2. options.inJustDecodeBounds = true;  
  3. BitmapFactory.decodeResource(getResources(), R.id.myimage, options);  
  4. int imageHeight = options.outHeight;  
  5. int imageWidth = options.outWidth;  
  6. String imageType = options.outMimeType;  

To avoid java.lang.OutOfMemory exceptions, check the dimensions of a bitmap before decoding it, unless you absolutely trust the source to provide you with predictably sized image data that comfortably fits within the available memory.

为了避免内存溢出异常,在解码前查看位图的尺寸,除非你完全相信来源,提供给你可预见的尺寸图像数据,容纳可用的内存。

Load a Scaled Down Version into Memory(加载一个小版本到内存)

Now that the image dimensions are known, they can be used to decide if the full image should be loaded into memory or if a subsampled version should be loaded instead. 

现在图像大小知道了。它们决定是整张图像或者缩略图被加载。

Here are some factors to consider:

这里有一下因数要考虑:

  • Estimated memory usage of loading the full image in memory.
  • 估计加载整张图片所需要的内存。
  • Amount of memory you are willing to commit to loading this image given any other memory requirements of your application.
  • 你使用内存加载图像的时候考虑你的应用任何其他的内存要求。
  • Dimensions of the target ImageView or UI component that the image is to be loaded into.
  • 图像被加载的目标ImageView的或者UI组件的大小。
  • Screen size and density of the current device.
  • 当前设备的屏幕尺寸和密度。

For example, it’s not worth loading a 1024x768 pixel image into memory if it will eventually be displayed in a 128x96 pixel thumbnail in an ImageView.

例如,一个1024x768像素的图像不值得加载到128x96像素的ImageView.

To tell the decoder to subsample the image, loading a smaller version into memory, set inSampleSize to true in your BitmapFactory.Options object.

告诉解码器是缩略图,加载较小的图像到内存,设置inSampleSize为true在你的BitmapFactory.Options对象。

For example, an image with resolution 2048x1536 that is decoded with an inSampleSize of 4 produces a bitmap of approximately 512x384.

例如,一个2048x1536的图像用inSampleSize等于4解码创建大约512x384的位图。

Loading this into memory uses 0.75MB rather than 12MB for the full image (assuming a bitmap configuration of ARGB_8888). 

加载它到内存使用075MB好于一整张图片12MB(假定是一个ABGB_8888组成的位图)。

Here’s a method to calculate a the sample size value based on a target width and height:

这是一个方法计算以样本为基础的宽和高:

[java]  view plain copy
  1. public static int calculateInSampleSize(  
  2.             BitmapFactory.Options options, int reqWidth, int reqHeight) {  
  3.     // Raw height and width of image (图像原始的宽和高)  
  4.     final int height = options.outHeight;  
  5.     final int width = options.outWidth;  
  6.     int inSampleSize = 1;  
  7.   
  8.     if (height > reqHeight || width > reqWidth) {  
  9.   
  10.         // Calculate ratios of height and width to requested height and width(根据宽高要求计算宽高比例)  
  11.         final int heightRatio = Math.round((float) height / (float) reqHeight);  
  12.         final int widthRatio = Math.round((float) width / (float) reqWidth);  
  13.   
  14.         // Choose the smallest ratio as inSampleSize value, this will guarantee  
  15.         // a final image with both dimensions larger than or equal to the  
  16.         // requested height and width.  
  17.         // 选择inSampleSize最小的比值,这样会保证图笑最终的尺寸大于等于要求的宽和高。  
  18.         inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;  
  19.     }  
  20.   
  21.     return inSampleSize;  
  22. }  

Note: Using powers of 2 for inSampleSize values is faster and more efficient for the decoder. However, if you plan to cache the resized versions in memory or on disk, it’s usually still worth decoding to the most appropriate image dimensions to save space.

注意:inSampleSize为2倍数的数值的时候解码最快而且更有效率。无论怎样,如果你计划缓存调整大小后的版本在内存或者磁盘上,通常还是最好解码最适合的图像尺寸保存。

To use this method, first decode with inJustDecodeBounds set to true, pass the options through and then decode again using the new inSampleSize value and inJustDecodeBounds set to false:

使用这个方法,在解码前设置inJustDecodeBounds为true,通过options的设置,然后解码,在一次使用新的inSampleSize数值和设置inJustDecodeBounds为false:

[java]  view plain copy
  1. public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,  
  2.         int reqWidth, int reqHeight) {  
  3.   
  4.     // First decode with inJustDecodeBounds=true to check dimensions(首先设置inJustDecodeBounds=true,查看尺寸)  
  5.     final BitmapFactory.Options options = new BitmapFactory.Options();  
  6.     options.inJustDecodeBounds = true;  
  7.     BitmapFactory.decodeResource(res, resId, options);  
  8.   
  9.     // Calculate inSampleSize 计算inSampleSize  
  10.     options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);  
  11.   
  12.     // Decode bitmap with inSampleSize set(通过设置inSampleSize解码位图)  
  13.     options.inJustDecodeBounds = false;  
  14.     return BitmapFactory.decodeResource(res, resId, options);  
  15. }  

This method makes it easy to load abitmap of arbitrarily large size into an ImageView that displays a 100x100 pixel thumbnail,as shown in the following example code:

这个方法使ImageView容易加载一个任意大小的位图来显示100X100像素的缩略图,下面是示例代码。


[java]  view plain copy
  1. mImageView.setImageBitmap(  
  2.     decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100100));  


You can follow a similar process to decode bitmaps from other sources, by substituting the appropriate BitmapFactory.decode* method as needed.
你可以效仿类似的过程去解码位图根据其他的原因,替代合适的BitmapFactory.decode*方法根据需要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值