您的位置:首页 > 其它

如何优化加载大位图(BitmapFactory使用系列)

2014-03-21 11:23 603 查看
Loading Large Bitmaps Efficiently
如何优化加载大位图

Images come in all shapes and sizes.In many cases they are larger than required for a typical application userinterface (UI). For example, the system Gallery application displays photostaken using your
Android devices's camera which are typically much higherresolution than the screen density of your device.
Given that you are working with limited memory, ideally you onlywant to load a lower resolution version in memory. The lower resolution versionshould match the size of the UI component that displays it. An image with ahigher resolution
does not provide any visible benefit, but still takes upprecious memory and incurs additional performance overhead due to additional onthe fly scaling.

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

图片有各种形状和大小。在很多情况下,这些图片的大小超过我们应用程序的需要,例如用手机拍摄的图片。

假如,你的应用程序只有有限的内存容量,最理想的做法是在内存中加载低分辨率的图像版本。低版本的图像需要适应设备屏幕的大小。一张高分辨率的图片不仅不会改善显示质量,而且还会影响应用程序的性能。

这个课程将讲述如何将一些大的位图压缩成少于应用程序使用内存容量的小图片。

ReadBitmap Dimensions and Type

读取位图的尺寸和类型

The
BitmapFactory
class
providesseveral decoding methods (
, int, int, android.graphics.BitmapFactory.Options)]decodeByteArray()
,
decodeFile()
,
decodeResource()
,
etc.)for creating a
Bitmap
from
various sources.Choose the most appropriate decode method based on your image data source.These methods attempt to allocate memory for the constructed bitmap andtherefore can easily result in an
OutOfMemory
exception.
Each typeof decode method has additional signatures that let you specify decodingoptions via the
BitmapFactory.Options
class.
Setting the
inJustDecodeBounds
property
to
true
while decoding avoidsmemory allocation, returning
null
for
the bitmap objectbut setting
outWidth
,
outHeight
and
outMimeType
.
Thistechnique allows you to read the dimensions and type of the image data prior toconstruction (and memory allocation) of the bitmap.

BitmapFactory类提供了几个解码方法能够从各种源文件中创建Bitmap对象,例如(, int, int, android.graphics.BitmapFactory.Options)]decodeByteArray(), decodeFile(),decodeResource()等)。我们需要根据图片的格式选择合适的解码方法。这些方法都尝试去为创建好的Bitmap对象分配内存,但是这样做会很容易导致
OutOfMemory
的异常。每种类型的解码方法,你都需要通过
BitmapFactory.Options
类来指定参数值。将
inJustDecodeBounds
参数值设定为true的时候,解码过程中将不为对象分配内容,但是会将图片的尺寸等信息通过
BitmapFactory.Options
对象的
outWidth
,
outHeight
outMimeType
值反馈。

如下代码所示:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);

//解码完成后,[code]outWidth
,
outHeight
outMimeType
值将包含图片的尺寸大小
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;[/code]

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

为了避免
java.lang.OutOfMemory
异常,需要在真正解码之前,通过上面代码描述的方法获取图片的真实尺寸。

Load aScaled Down Version into Memory

将一个压缩版本加载到内存中

Now that the image dimensions are known, they can be used todecide if the full image should be loaded into memory or if a subsampledversion should be loaded instead. Here are some factors to consider:

至此,你可以通过图片的尺寸来觉得是否使用一个一个压缩的版本来加载到内存中。下面有一些因素,你需要考虑到:


· Estimated memory usage of loading the fullimage in memory.
· Amount of memory you are willing to commit toloading this image given any other memory requirements of your application.
· Dimensions of the target
ImageView
or
UIcomponent that the image is to be loaded into.
· Screen size and density of the currentdevice.
1、
预估加载整个图片后,需要占用的内存大小;


2、
应用程序关于加载图片时使用内存大小的需求;


3、
存放图片的
ImageView
或者
UI
组件的尺寸;


4、
屏幕大小。


To tell the decoder to subsample theimage, loading a smaller version into memory, set
inSampleSize
to
true
in
your
BitmapFactory.Options
object.
For example,an image with resolution 2048x1536 that is decoded with an
inSampleSize
of
4 produces abitmap of approximately 512x384. Loading this into memory uses 0.75MB ratherthan 12MB for the full image (assuming a bitmap configuration of
ARGB_8888
).
Here’sa method to calculate a sample size value that is a power of two based on atarget width and height:
为了能够将图片压缩,你需要将
inSampleSize
的值设定为
true
。下面是计算压缩比例的例子:


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


Note: A power of two valueis calculated because the decoder uses a final value by rounding down to thenearest power of two, as per the
inSampleSize
documentation.

To use this method, first decode with
inJustDecodeBounds
set
to
true
, pass theoptions through and then decode again using the new
inSampleSize
value
and
inJustDecodeBounds
set
to
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);
}


This method makes it easy to load a bitmap of arbitrarily largesize into an
ImageView
that
displays a100x100 pixel thumbnail, as shown in the following example code:

mImageView.setImageBitmap(
    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));


You can follow a similar process to decode bitmaps from othersources, by substituting the appropriate
, int, int, android.graphics.BitmapFactory.Options)]BitmapFactory.decode*
method
as needed.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: