当前位置: 首页 > 知识库问答 >
问题:

JAVAlang.OutOfMemoryError:位图大小超过ListView中的VM预算,并且延迟加载图像

慕承恩
2023-03-14

我有一个列表视图,它可能有无限滚动加载的无限项目。

列表视图中的每个项目都有一个或两个我正在懒洋洋地加载的图像。

一切都很好,但当我滚动很长时间,它崩溃了,这在日志猫

 08-07 15:26:25.231: E/AndroidRuntime(30979): FATAL EXCEPTION: Thread-60
08-07 15:26:25.231: E/AndroidRuntime(30979): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
08-07 15:26:25.231: E/AndroidRuntime(30979):    at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
08-07 15:26:25.231: E/AndroidRuntime(30979):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:493)
08-07 15:26:25.231: E/AndroidRuntime(30979):    at com.test.android.helper.LazyImageLoader.decodeFile(LazyImageLoader.java:171)
08-07 15:26:25.231: E/AndroidRuntime(30979):    at com.test.android.helper.LazyImageLoader.getBitmap(LazyImageLoader.java:112)
08-07 15:26:25.231: E/AndroidRuntime(30979):    at com.test.android.helper.LazyImageLoader.access$2(LazyImageLoader.java:106)
08-07 15:26:25.231: E/AndroidRuntime(30979):    at com.test.android.helper.LazyImageLoader$ImageLoader.run(LazyImageLoader.java:197)

在我的lazy image loader中,我将位图存储在WeakHashMap中。所以垃圾收集器应该收集位图,对吗?

我懒惰的图像加载器的工作原理是这样的。

我使用url和对Imageview的引用从我的适配器调用displayImage()

public void displayImage(String url, ImageView imageView, int defaultImageResourceId){

        latestImageMetaData.put(imageView, url);

        if(weakhashmapcache.containsKey(url)){
            imageView.setImageBitmap(weakhashmapcache.get(url));
        }
        else{
            enqueueImage(url, imageView, defaultImageResourceId);
            imageView.setImageResource(defaultImageResourceId);
        }
    }

因此,如果我在缓存中找到图像,我会直接设置它,否则我会使用函数enqueueImage()将其排队。

private void-enqueueImage(字符串url,ImageView-ImageView,int-defaultImageResourceId){Image-Image=new-Image(url,ImageView,defaultImageResourceId);downloadqueue.add(Image); // downloadQueue是一个阻塞队列,等待添加图像//如果队列即将满,则删除队列中前面的元素,因为它们无论如何都不可见迭代器迭代器=downloadQueue。迭代器();while(iterator.hasNext()

And my image loader thread is this - 

class ImageLoader extends Thread {

    public void run() {
        Image firstImageInQueue;

        try {
            while((firstImageInQueue = downloadQueue.take()) != SHUTDOWN_TOKEN)
            {
                Bitmap imageBitmap = getBitmap(firstImageInQueue.url);

                if(imageBitmap != null){
                    weakhashmap.put(firstImageInQueue.url, imageBitmap);
                    BitmapDisplayer displayer = new BitmapDisplayer(imageBitmap, firstImageInQueue.imageView, firstImageInQueue.url, firstImageInQueue.defaultImageResourceId);
                    Activity activity = (Activity)firstImageInQueue.imageView.getContext();
                    activity.runOnUiThread(displayer);
                }
            }
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
        finally {
            imageLoaderTerminated = true;
        }
    } 
}

getBitmap()只是从url中获取图像并将其解码为位图对象。BitmapDisplayer只是一个Runnable,它将图像设置为线程上UI图像视图。

我做错了什么?

共有2个答案

宗政天逸
2023-03-14

尝试通用图像加载器

这是一个开源项目,他们有关于如何使用它的博客文章。我已经在几个项目中使用过它,即使在长长的列表中我也没有问题。

享受!!

茅秦斩
2023-03-14

这是一场噩梦,几天后

不要将所有位图都存储在缓存中。保持它在磁盘缓存和内存缓存之间交换。存储的位图数量取决于通过调用

int memClass=((活动管理器)上下文。getSystemService(Context.ACTIVITY_SERVICE))。getMemoryClass()

我使用了LruCache而不是WeakHashMap缓存。LruCache在支持包中可用。用LruCache替换现有的WeakHashMap实现非常容易。Android在缓存位图上也有一个漂亮的留档。

Jake Wharton的DiskLruCache是管理磁盘缓存的好方法。

如果不需要,不要下载巨大的位图。试着买一个刚好适合你需要的尺码。

使用BitmapFactory。选项您可以在图像质量上做出一些权衡,以便在内存缓存中保存更多图像。

如果你认为我们还有什么可以做的,请补充。

 类似资料:
  • 在我的应用程序中,当我试图启动它时,会强制关闭,错误指向“setContentView(R.layout.Menu);”布局的一部分。在XML文件中,它在我的布局中显示“OutOfMemoryError”图像视图。我真的很困惑。请引导我进一步行动。 编辑: 我的应用程序使用数据库,第一次解析一些XML数据并插入Sqlite数据库。我的Outofmemory问题只在第一次出现。第二次效果很好。我试过

  • 问题内容: 我正在使用ListView来显示一些图像和与这些图像相关的标题。我正在从互联网上获取图像。有没有一种方法可以延迟加载图像,以便在显示文本时不阻止UI并在下载图像时显示它们? 图像总数不固定。 问题答案: 这是我创建的用于保存应用程序当前正在显示的图像的内容。请注意,此处使用的“ Log”对象是我在Android内部最终Log类周围的自定义包装。

  • 问题内容: 这是一个非常常见的场景:在ListView中显示必须从Internet下载的图像。 现在,我有一个用于ArrayView的自定义子类ArrayAdapter。在ArrayAdapter的getView()实现中,我产生了一个单独的线程来加载图像。加载完成后,它将查找适当的ImageView并使用ImageView.setImageDrawable()设置图像。因此,我使用的解决方案与此

  • Flask 通常配合装饰器使用,装饰器使用非常简单,而且使您可以将 URL 和处理它的函数 放在一起。然而这种方法也有一种不足: 这就意味着您使用装饰器的代码必须在前面导入, 否则 Flask 将无法找到您的函数。 这对于需要很快导入的应用程序来说是一个问题,这种情况可能出现在类似谷歌的 App Engine 这样的系统上。所以如果您突然发现您的引用超出了这种方法可以处理 的能力,您可以降级到中央

  • 问题内容: 我正在开发一个eshop。在基于类别的产品页面上,我放置了一些基于javascript的过滤器。但是,如果类别具有很多产品,则会出现问题。该链接具有与我相似的功能… 这个页面多么缓慢,却超过2mb !!! 对我来说,每个产品都需要一半的K字节,但是图像是个问题。.因此,我正在寻找如何延迟加载图像的方法。由于与该网站不同,我的页面具有分页功能,因此我认为加载仅对页面可见的图像是一种解决方

  • 我有一个列表视图,它显示带有缩略图图像的视频,我使用光标适配器(使用ContentProvider获取)。问题是随着列表项数量的增加,列表视图性能变得非常差。请让我知道使其延迟加载的最佳方法。 新:我终于找到了一些解决办法。这对我来说很好。如果你有什么建议,请告诉我。我的新代码在这里。(它使用具有生产者-消费者模式和bacground线程的堆栈进行处理) @覆盖公共空bindView(视图视图、上