Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android Bitmap Efficient Load #50

Open
yunshuipiao opened this issue May 27, 2019 · 0 comments
Open

Android Bitmap Efficient Load #50

yunshuipiao opened this issue May 27, 2019 · 0 comments
Labels

Comments

@yunshuipiao
Copy link
Owner

Android Bitmap Efficient Load

[TOC]

文章转载:https://juejin.im/post/5b0e6e6a5188251570336972

将大图加载到内存中总是令人痛苦,经常会造成 OOM。Android系统的内存有限

建议使用Picasso或Glide来加载图片。没有必要重新发明轮子。

将图片加载到内存中

只需要使用BitmapFactory来解码你的图片.

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage);
imageView.setImageBitmap(bitmap);

看一下这张解码过的图片在内存中实际占据的空间大小。

bitmap.getByteCount()方法将返回bitmap的大小。 这张图片在内存中的大小为12262248字节,相当于12.3 MB。是的,你可能会感到困惑。因为这张图片在磁盘上的实际大小约为3.5 MB,而getByteCount()方法返回的值远大于它。原因如下:

存储在磁盘上的图片是被压缩过的(以JPG,PNG或类似的格式存储)。 一旦将图片加载到内存中,它就不再被压缩,并占用尽可能多的图片的所有像素所需的内存空间。

加载大图的步骤

  1. 获取图片的宽和高
  2. 根据图片的宽和高计算缩放比
  3. 根据缩放比将图片加载到内存中。

BitmapFactory.Options

BitmapFactory.Options options = new BitmapFactory.Options(); 
options.inJustDecodeBounds = true; 
BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage, options);

我们将BitmapFactory.Options实例传递给BitmapFactory.decodeSource()方法。options.inJustDecodeBounds = true 是什么意思?这句代码是指我们不想将图片加载到内存中。我们只想获取图片的相关信息(宽度,高度等),并使用这些信息来计算缩放比例。

我们运行这段代码并打印图片的信息:

options.outHeight : 1126
options.outWidth : 2000
options.bitmap : null

Reducing Image Size (In Memory)

现在我们需要计算inSampleSize。什么是inSampleSize? inSampleSize是BitmapFactory.Options类的一个属性,用于设置图片的缩放比。

如果我们有一张尺寸为1000x1000的图片,并且在解码之前设置inSampleSize的值为2, 那么解码之后,我们将得到一张尺寸为500x500的图片。 如果我们有一张尺寸为200x400的图片,并且在解码之前设置inSampleSize的值为5, 那么解码之后,我们将得到一张尺寸为40x80的图片。

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inSampleSize = 3; 
BitmapFactory.decodeResource(getResources(), R.mipmap.hqimage, options);

我们可以直接这样做吗?不能,因为我们不知道图片大小是多少。如果它是小图片,并且我们使其更小,那么我们的用户看到的就是一些像素而不是图像。有一些图片需要缩放5倍,另一些图片则需要缩放2倍。我们不能将缩放比设置为一个常数,所以我们必须根据图片的大小来计算它的值。

如何计算inSampleSize的值取决于您。官方建议,计算结果是2的幂次方。

这里我们将inJustDecodeBounds的值设为false,并获得了一个bitmap对象。现在,bitmap.getByteCount()方法返回的图片大小是3.1 MB。这是它在内存中的大小。正如我之前说过的,图片存储在磁盘上时会被压缩。当我们将它们加载到内存中时它们会占据更大的内存空间。通过上面这种方法,我们将它在内存中占据的空间大小从12.3 MB减少到了3.1 MB,减少了75%。

Reducing Image Size (In Disk)

我们还可以使用Bitmap的compress方法对磁盘上的图片进行压缩。

我们来看看在不改变图片质量的情况下图片被压缩后的大小。 100表示与原图保持相同的质量。

ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
byte[] bitmapdata = bos.toByteArray();

通过计算得到图片在磁盘上的大小为1.6 MB。

我们把compress方法中的质量参数改为50,并再次计算图片大小。

bitmap.compress(Bitmap.CompressFormat.JPEG, 50, bos);

通过计算得到图片在磁盘上的大小为24.4 KB。

在改变compress方法中的质量参数的时候,压缩格式应该是.JPEG。设置为PNG格式的时候,修改是无效的。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant