android decodestream,BitmapFactory.decodeResource v.s. BitmapFactory.decodeStream in Android

首先分析一下 BitmapFactory.decodeResource 的实现代码:

public static Bitmap decodeResource(Resources res, int id, Options opts) {

Bitmap bm = null;

InputStream is = null;

try {

final TypedValue value = new TypedValue();

is = res.openRawResource(id, value);

bm = decodeResourceStream(res, value, is, null, opts);

} catch (Exception e) {

} finally {

try {

if (is != null) is.close();

} catch (IOException e) {

// Ignore

}

}

return bm;

}

可以看出 decodeResource 主要是通过调用 decodeResourceStream 来解码图片的。我们看看

decodeResourceStream 的实现:

public static Bitmap decodeResourceStream(Resources res, TypedValue value,

InputStream is, Rect pad, Options opts) {

if (opts == null) {

opts = new Options();

}

if (opts.inDensity == 0 && value != null) {

final int density = value.density;

if (density == TypedValue.DENSITY_DEFAULT) {

opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;

} else if (density != TypedValue.DENSITY_NONE) {

opts.inDensity = density;

}

}

if (opts.inTargetDensity == 0 && res != null) {

opts.inTargetDensity = res.getDisplayMetrics().densityDpi;

}

return decodeStream(is, pad, opts);

}

我们看到,decodeResourceStream

会根据图片本身的密度以及屏幕的密度,设置合适的inDensity和inTargetDensity,以使 Android

可以对图片资源进行自适应缩放。设置完这两个参数,接着就直接调用 decodeStream 来完成解码任务。

我们继续分析 decodeStream 方法:

public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {

// 此处省略部分代码...

Bitmap bm;

if (is instanceof AssetManager.AssetInputStream) {

bm = nativeDecodeAsset(((AssetManager.AssetInputStream) is).getAssetInt(),

outPadding, opts);

} else {

// pass some temp storage down to the native code. 1024 is made up,

// but should be large enough to avoid too many small calls back

// into is.read(...) This number is not related to the value passed

// to mark(...) above.

byte [] tempStorage = null;

if (opts != null) tempStorage = opts.inTempStorage;

if (tempStorage == null) tempStorage = new byte[16 * 1024];

bm = nativeDecodeStream(is, tempStorage, outPadding, opts);

}

return finishDecode(bm, outPadding, opts);

}

我们看到,在 decodeStream 里面,是直接调用了 native 接口来解码图片的。那么,decodeResource

和 decodeStream 的区别到底体现在哪里呢?秘密藏在最后一句里: finishDecode(...)。

我们具体看一下 finishDecode 的实现:

private static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) {

if (bm == null || opts == null) {

return bm;

}

final int density = opts.inDensity;

if (density == 0) {

return bm;

}

bm.setDensity(density);

final int targetDensity = opts.inTargetDensity;

if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {

return bm;

}

byte[] np = bm.getNinePatchChunk();

final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);

if (opts.inScaled || isNinePatch) {

float scale = targetDensity / (float)density;

// TODO: This is very inefficient and should be done in native by Skia

final Bitmap oldBitmap = bm;

bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),

(int) (bm.getHeight() * scale + 0.5f), true);

oldBitmap.recycle();

if (isNinePatch) {

np = nativeScaleNinePatch(np, scale, outPadding);

bm.setNinePatchChunk(np);

}

bm.setDensity(targetDensity);

}

return bm;

}

其实,我们只需看那句 "TODO" 注释及其附近的代码就会明白,原来 Android

会在java层做效率较低的自适应缩放。而前面我们提到,decodeResourceStream 方法里,会设置 inDensity 和

inTargetDensity 两个参数,这两个参数就是在这里起作用的。

总结如下:

BitmapFactory.decodeResource 加载的图片可能会经过缩放

该缩放目前是放在 java 层做的,效率比较低,而且需要消耗 java

层的内存。因此,如果大量使用该接口加载图片,容易导致OOM错误

BitmapFactory.decodeStream 不会对所加载的图片进行缩放,相比之下占用内存少,效率更高

这两个接口各有用处,如果对性能要求较高,则应该使用 decodeStream;如果对性能要求不高,且需要 Android

自带的图片自适应缩放功能,则可以使用 decodeResource。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值