通过关注this link,我编写了以下代码来显示sdcard中的大图像位图。
try {
InputStream lStreamToImage = context.getContentResolver().openInputStream(Uri.parse(imagePath));
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(lStreamToImage, null, options);
options.inSampleSize = 8; //Decrease the size of decoded image
options.inPreferredConfig = Bitmap.Config.ARGB_4444;
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeStream(lStreamToImage, null, options);
} catch(Exception e){}
image.setImageBitmap(bitmap);
但它没有返回位图(我的意思是它返回null)。在logcat中,它重复显示以下消息
08-02 17:21:04.389: D/skia(19359): --- SkImageDecoder::Factory returned null
如果我要评论 options.inJustDecodeBounds 行并重新运行它,它可以正常但很慢。我在上面提供的开发人员指南链接说使用 inJustDecodeBounds 来有效地加载位图。
请告诉我我做错了什么。
答案 0 :(得分:2)
inJustDecodeBounds
不加载位图。这就是它的重点。它加载位图的尺寸而不加载实际的位图,因此您可以在实际加载位图之前进行任何预处理或检查位图。例如,如果您遇到内存问题,并且需要检查加载位图是否会导致程序崩溃,这很有用。
你的位图可能加载缓慢的原因是因为它可能非常大而且SD卡非常慢。
修改强>:
如果设置为true,解码器将返回null(无位图),但仍将设置out ...字段,允许调用者查询位图而无需为其像素分配内存。
编辑2:
使用Google提供的示例查看您的代码,看起来您正在做相对相同的事情。它返回null的原因可能是你的InputStream
在第一次解码时已被修改,因此不会从位图的内存地址的开头开始(它们使用资源ID而不是InputStream
。
根据您提供的代码,这是我的想法。无论第一次解码给你什么,你总是将样本大小设置为8。谷歌第一次解码的原因是要弄清楚位图的实际大小与他们想要的大小。他们确定位图是ZxZ维度并且他们想要YxY维度,因此他们计算他们应该从第二次解码中使用的samplesize
。你不是这样做的。您只是检索位图的尺寸而不是使用它们。然后,您将样本大小设置为硬编码8
,将其交换为硬编码的ARGB_4444
位图,然后将完整位图解码到内存中。换句话说,这三行没有被使用:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(lStreamToImage, null, options);
设置inJustDecodeBounds
只会为您提供位图的尺寸,而不会将位图放入内存中。它不会使它更有效率。它意味着允许你在较小的内存空间中加载位图,如果它们太大,因为你可以预先决定它应该是什么尺寸而不解码整个东西。)
解码位图的原因很慢可能仅仅是CPU的事情。根据位图的大小,您从SD卡中加载InputStream
的位图,这本身就是一个缓慢的操作。