0

通过点击此链接,我编写了以下代码来显示来自 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来有效地加载位图。

请告诉我我在哪里做错了。

4

1 回答 1

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 的问题。根据位图的大小,您正在InputStream从 SD 卡加载位图,这本身就是一个缓慢的操作。

于 2012-08-02T12:17:33.430 回答