安卓系统:BitmapFactory解码流方法出现内存不足错误



我已经为这个问题纠结了一段时间。不过,我还有一些希望。

我的一项活动是使用AsyncTask下载图像。它将图像保存在位图中,然后在图像视图中显示。这是代码:

@Override
    protected String doInBackground(String... urls) {
        try {
            URL url = new URL(urls[0]);
            // First decode with inJustDecodeBounds=true to check dimensions
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(url.openConnection()
                    .getInputStream(), null, options);
            // Calculate inSampleSize
            options.inSampleSize = calculateInSampleSize(options, 270, 173);
            // Decode bitmap with inSampleSize set
            options.inJustDecodeBounds = false;
            options.inPurgeable = true;
            options.inInputShareable = true;
            bmp = BitmapFactory.decodeStream(url.openConnection()
                    .getInputStream(), null, options);
        } catch (Exception e) {
            Log.e(MainActivity.class.toString(),
                    "No se pudo descargar la imagen");
        }
        return "";
    }
    @Override
    protected void onPostExecute(String result) {
        if (bmp != null) {
            imagenNoticia.setImageBitmap(bmp);
            imagenNoticia.setVisibility(View.VISIBLE);
        }
    }
}

但是,在浏览应用程序一段时间后,通过打开和关闭此活动,我在代码BitmapFactory.decodeStream的行中得到了一个OutOfMemoryError。我相信此活动永远不会重复,所以我一次只选择一个类型。

正如你们所看到的,我已经使用了一些关于有效解码位图的最佳实践。类似于对接收到的图像进行下采样(在JustDecodeBounds中)。

我想知道我还能做些什么来避免这个错误<有人知道吗>

接下来是错误。

谢谢!任何帮助都将不胜感激。

12-16 18:19:17.686: E/AndroidRuntime(13321): FATAL EXCEPTION: AsyncTask #1
12-16 18:19:17.686: E/AndroidRuntime(13321): java.lang.RuntimeException: An error         occured while executing doInBackground()
12-16 18:19:17.686: E/AndroidRuntime(13321):    at     android.os.AsyncTask$3.done(AsyncTask.java:299)
12-16 18:19:17.686: E/AndroidRuntime(13321):    at     java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
12-16 18:19:17.686: E/AndroidRuntime(13321):    at     java.util.concurrent.FutureTask.setException(FutureTask.java:124)
12-16 18:19:17.686: E/AndroidRuntime(13321):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
12-16 18:19:17.686: E/AndroidRuntime(13321):    at java.util.concurrent.FutureTask.run(FutureTask.java:137)
12-16 18:19:17.686: E/AndroidRuntime(13321):    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
12-16 18:19:17.686: E/AndroidRuntime(13321):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
12-16 18:19:17.686: E/AndroidRuntime(13321):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
12-16 18:19:17.686: E/AndroidRuntime(13321):    at java.lang.Thread.run(Thread.java:856)
12-16 18:19:17.686: E/AndroidRuntime(13321): Caused by: java.lang.OutOfMemoryError
12-16 18:19:17.686: E/AndroidRuntime(13321):    at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
12-16 18:19:17.686: E/AndroidRuntime(13321):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:652)
12-16 18:19:17.686: E/AndroidRuntime(13321):    at     com.mobilemedianet.larepublica.activity.NotiDetalle$CargarNoticias.doInBackground(NotiDetalle.java:496)
12-16 18:19:17.686: E/AndroidRuntime(13321):    at com.mobilemedianet.larepublica.activity.NotiDetalle$CargarNoticias.doInBackground(NotiDetalle.java:1)
12-16 18:19:17.686: E/AndroidRuntime(13321):    at android.os.AsyncTask$2.call(AsyncTask.java:287)
12-16 18:19:17.686: E/AndroidRuntime(13321):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
12-16 18:19:17.686: E/AndroidRuntime(13321):    ... 5 more

我认为您遇到了一个变量范围问题,谁拥有bmp变量?它从你的代码中清除了吗?AsyncTask是否在imageview设置位图后被清空?否则你就泄露了bmp(它没有被释放!)。

"重写异步任务"选项

我认为您是AsyncTask,应该扩展AsyncTask<String, Void, Bitmap>给您(并将行更改为我在这里所写的内容):

@Override
protected String doInBackground(String... urls) {
    try {
        // omitted some lines
        return BitmapFactory.decodeStream(url.openConnection()
                .getInputStream(), null, options);
    } catch (Exception e) {
        Log.e(MainActivity.class.toString(),
                "No se pudo descargar la imagen");
    }
    return null;
}
@Override
protected void onPostExecute(Bitmap result) {
    if (result != null) {
        imagenNoticia.setImageBitmap(result);
        imagenNoticia.setVisibility(View.VISIBLE);
    }
}

在执行了onPostExecute之后,上述AsyncTask不保留任何位图引用。

其他选项

如果您不想执行上述操作,则应考虑在onPostExecute中最后取消bmp变量,并最终在AsyncTask中实现onCancelled回调,如果且仅当您对任务调用cancel,并在onCancelled回调中清除bmp ref,则(因为onPostExecute在这种情况下不会运行)

您有对两个位图的引用:一个在视图中,另一个在AsyncTask中。你能做什么,至少在理论上:

1) 将下载的位图保存到磁盘(sd卡等)。在这种情况下,您可以先停止使用第一个图像,然后再使用第二个图像。

2) 将下载图像转移到一个单独的过程中。它将有自己的堆报价。缩放可能应该进行相同的(第二个)过程。在XML中,活动和服务具有流程属性。一般来说,杀死进程是杀死Java垃圾的好方法。

3) 在流程和活动的生命周期中存在低内存回调。也许这是你可以在视图中释放图像的时刻(我自己没有尝试过,甚至不确定这些回调是否真的被调用了)。

4) 也许您可以将应用程序的不同活动放在不同的流程中(这取决于您的应用程序是什么)。

最新更新