OutOfMemoryError通过DefaultHttpClient加载位图

时间:2012-11-02 22:38:39

标签: android apache-httpclient-4.x

我有一个简单的问题:虽然我正在使用sampleSize,但我的代码甚至没有到达BitmapFactory代码,因为DefaultHttpClient已经抛出了异常。

这是我的代码:

                DefaultHttpClient client = new DefaultHttpClient();
                HttpGet request = new HttpGet(mSongInfo.imageLarge);
                HttpResponse response = client.execute(request);
                int sampleSize = 1;
                while (response.getEntity().getContentLength() / sampleSize
                        / sampleSize > 100 * 1024) {
                    sampleSize *= 2;
                }
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inSampleSize = sampleSize;
                final Bitmap bitmap = BitmapFactory.decodeStream(response
                        .getEntity().getContent(), null, options);

以下是例外:

0   java.lang.OutOfMemoryError: (Heap Size=11463KB, Allocated=7623KB, Bitmap Size=9382KB)
1       at org.apache.http.util.ByteArrayBuffer.<init>(ByteArrayBuffer.java:53)
2       at org.apache.http.impl.io.AbstractSessionInputBuffer.init(AbstractSessionInputBuffer.java:82)
3       at org.apache.http.impl.io.SocketInputBuffer.<init>(SocketInputBuffer.java:98)
4       at org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:83)
5       at org.apache.http.impl.conn.DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.java:170)
6       at org.apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.java:106)
7       at org.apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:129)
8       at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:173)
9       at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
10      at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
11      at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:359)
12      at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
13      at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
14      at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
15      at de.goddchen.android.easysongfinder.fragments.SongFragment$1.run(SongFragment.java:79)
16      at java.lang.Thread.run(Thread.java:1027)

如您所见,代码甚至没有到达我检查图像大小(内容长度)并计算适当样本大小的部分。

我不知道简单地调用DefaultHttpClient.execute(...)已经将完整的内容加载到内存中。

我做错了吗?首先检索内容长度然后从InputStream开始阅读内容的正确方法是什么?

修改 为了避免显示如何从URL加载图像的常见答案:我已经知道如何做到这一点,我也发布了上面的代码,那你为什么要继续引用这个教程呢?我明确地明确了这个问题:为什么HttpClient.execute(...)已经取出整个内容并将其存储在内存中而不是向我提供正确的InputStream?请不要发布任何有关如何从URL加载Bitmap的初学者教程...

3 个答案:

答案 0 :(得分:1)

只需使用HttpUrlConnection即可获得该简单请求。

此外,您确定样本大小的方式是hackish,在解码为Bitmap之前的内容大小不是确定Bitmap字节分配的好方法,而是使用其维度。

答案 1 :(得分:1)

还要检查setFixedLengthStreamingMode上的方法setChunkedStreamingModeHttpURLConnection。考虑到它们,您可以在下载大图像时减少内存消耗。

仅供参考,您可以查看可能提供您尝试实现的功能的库。有些还支持缓存,这可能非常方便。

我知道的很少有

https://github.com/nostra13/Android-Universal-Image-Loader

https://github.com/novoda/ImageLoader

https://github.com/kaeppler/ignition

答案 2 :(得分:0)

我对从互联网上加载的图片有类似的问题,我修复此问题的方法是将图像保存在手机的临时位置(您可以使用内部或外部存储,无所谓)并加载来自那里。将图像字节保存在文件中,使用缓冲区,不要在单个操作上读写所有字节。

这种方式很好用。我现在没有示例代码,我没有找到我使用这种技术的项目,但你可以使用谷歌方式从http中保存二进制资源。

稍后修改: 另一个类似的问题在这里被问到:Regarding download image from url in android

稍后编辑

此流无法多次读取,在第一次读取时获取图像大小,然后转到另一个信息。这是您的错误的简短说明。编译器优化您的代码,以便能够从流中重新读取并将其放在内存中。发生这种情况时,会抛出OOM。