Android“尝试使用已回收的位图”错误?

19
我在一款Android应用程序中遇到了位图问题。它应该从网站下载图片,将其保存到设备上,将其作为位图加载到ArrayList中,并将其显示给用户。当应用程序首次启动时,所有这些都能够正常工作。然而,我为用户添加了一个刷新选项,其中包括删除图像并重新开始上述过程。
我的问题是:通过使用刷新选项,旧的图像仍然存在于内存中,我很快就会收到OutOfMemoryErrors的错误。因此,如果正在刷新图像,则需要运行数组列表并回收旧图像。但是,当应用程序尝试将新图片加载到ArrayList中时,它会崩溃,并出现“Trying to use recycled bitmap”错误。
据我所知,回收位图会销毁位图并释放其内存以供其他对象使用。如果我想再次使用位图,则必须重新初始化它。我相信当将新文件加载到ArrayList中时,我正在这样做,但仍有问题。非常感谢任何帮助,因为这非常令人沮丧。以下是问题代码。谢谢!
public void fillUI(final int refresh) { 
// Recycle the images to avoid memory leaks
if(refresh==1) {
    for(int x=0; x<images.size(); x++)
        images.get(x).recycle();
    images.clear();
    selImage=-1; // Reset the selected image variable
}
final ProgressDialog progressDialog = ProgressDialog.show(this, null, this.getString(R.string.loadingImages));
// Create the array with the image bitmaps in it
new Thread(new Runnable() {
    public void run() {
        Looper.prepare();
        File[] fileList = new File("/data/data/[package name]/files/").listFiles();
        if(fileList!=null) {
            for(int x=0; x<fileList.length; x++) {
                try {
                    images.add(BitmapFactory.decodeFile("/data/data/[package name]/files/" + fileList[x].getName()));
                } catch (OutOfMemoryError ome) {
                    Log.i(LOG_FILE, "out of memory again :(");
                }
            }
            Collections.reverse(images);
        }
        fillUiHandler.sendEmptyMessage(0);
    }
}).start();

fillUiHandler = new Handler() {
    public void handleMessage(Message msg) {
        progressDialog.dismiss();
    }
};

}

->

}

2个回答

19

在这里,您实际上不需要调用recycle方法。刷新按钮应该只清除数组,垃圾回收器稍后将释放内存。如果出现OutOfMemory,则意味着某些其他对象仍然引用旧图像,垃圾回收器无法删除它们。

我可以假设一些ImageView显示您的位图,并保留对该位图的引用。在仍在显示旧位图时,无法删除旧位图。因此,一个可能的解决方案是先清除ImageVIew,然后清除数组并填充新图像。

Recycle释放内存,但某个ImageView仍在显示位图,在回收后它不能这样做,这就是为什么会出现“Trying to use recycled bitmap”的原因。

这些都只是假设,因为我看不到您的完整代码。


3
“您实际上不需要在这里调用recycle方法”。嗯,有趣。到目前为止,我在网上阅读的内容也认为这是必须调用的方式。我一直都在调用它。使用大量位图时我也曾经遇到内存问题。减少内存问题的好方法是使用软引用缓存,就像Romain Guy建议的那样。他例如在http://shelves.googlecode.com/svn/trunk/Shelves/src/org/curiouscreature/android/shelves/util/ImageUtilities.java中使用了它。关于SoftReferences: http://java.sun.com/j2se/1.5.0/docs/api/java/lang/ref/SoftReference.html - Mathias Conradt
4
回收利用是好的,但不是必须的。垃圾回收器无论如何都会清理内存。回收利用只是可以更快地清理它。这是我的理解方式。 - Fedor
1
谢谢Fedor!在清除和重新创建数组之前,我确保将使用位图的任何视图都设置为null,这样就解决了问题。 :) - Mike

4

如果内存很大,最好自己回收位图。 GC 无法控制。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接