美文网首页
有效加载大位图

有效加载大位图

作者: 鹿小纯0831 | 来源:发表于2019-03-07 16:39 被阅读9次

注意:有几个库遵循加载图像的最佳实践。 您可以在应用中使用这些库以最优化的方式加载图像。 我们建议使用Glide库,尽可能快速,平稳地加载和显示图像。 其他受欢迎的图像加载库包括Square的Picasso和Facebook的Fresco。 这些库简化了与Android上的位图和其他类型图像相关的大多数复杂任务。

图像有各种形状和大小。 在许多情况下,它们比典型应用程序用户界面(UI)所需的大。 例如,系统图库应用程序显示使用Android设备的相机拍摄的照片,这些照片的分辨率通常远高于设备的屏幕密度。

鉴于您正在使用有限的内存,理想情况下您只想在内存中加载较低分辨率的版本。 较低分辨率版本应与显示它的UI组件的大小相匹配。 具有更高分辨率的图像不提供任何可见的益处,但仍然占用宝贵的存储器并且由于额外的飞行缩放而产生额外的性能开销。

本课程将引导您通过在内存中加载较小的子采样版本来解码大型位图,而不会超出每个应用程序的内存限制。

读取位图尺寸和类型

BitmapFactory类提供了几种解码方法(decodeByteArray()decodeFile()decodeResource()等),用于从各种源创建位图。 根据图像数据源选择最合适的解码方法。 这些方法尝试为构造的位图分配内存,因此很容易导致OutOfMemory异常。 每种类型的解码方法都有其他签名,可让您通过BitmapFactory.Options类指定解码选项。 解码时将inJustDecodeBounds属性设置为true可避免内存分配,为位图对象返回null但设置outWidthoutHeightoutMimeType。 此技术允许您在构造(和内存分配)位图之前读取图像数据的尺寸和类型。

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异常,请在解码之前检查位图的尺寸,除非您完全信任该源为您提供可预测大小的图像数据,这些数据可以轻松地放入可用内存中。

将缩小版本加载到内存中

既然图像尺寸已知,它们可用于决定是否应将完整图像加载到内存中,或者是否应加载子采样版本。 以下是需要考虑的一些因素:

  • 估计在内存中加载完整映像的内存使用情况。
  • 在给定应用程序的任何其他内存要求的情况下,您愿意承诺加载此映像的内存量。
  • 要加载图像的目标ImageView或UI组件的尺寸。
  • 屏幕尺寸和当前设备的密度。

例如,如果最终将在ImageView中以128x96像素的缩略图显示,则不值得将1024x768像素图像加载到内存中。

要告诉解码器对图像进行子采样,将较小的版本加载到内存中,请在BitmapFactory.Options对象中将inSampleSize设置为true。 例如,使用inSampleSize为4解码的分辨率为2048x1536的图像会产生大约512x384的位图。 将其加载到内存中对于完整图像使用0.75MB而不是12MB(假设ARGB_8888的位图配置)。 这是一种根据目标宽度和高度计算样本大小值的方法,该值为2的幂:

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

注意:计算两个幂的幂是因为解码器使用最终值,通过向下舍入到最接近的2的幂,根据inSampleSize文档。

要使用此方法,首先使用inJustDecodeBounds设置为true进行解码,传递选项然后使用新的inSampleSize值再次解码,并将inJustDecodeBounds设置为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);
}

此方法可以轻松地将任意大尺寸的位图加载到显示100x100像素缩略图的ImageView中,如以下示例代码所示:

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

您可以按照类似的过程解码来自其他来源的位图,方法是根据需要替换相应的BitmapFactory.decode *方法。

相关文章

网友评论

      本文标题:有效加载大位图

      本文链接:https://www.haomeiwen.com/subject/yffhpqtx.html