如何在android中使用imageloader释放位图内存?

Posted

技术标签:

【中文标题】如何在android中使用imageloader释放位图内存?【英文标题】:How to release memory of bitmap using imageloader in android? 【发布时间】:2015-09-29 06:22:36 【问题描述】:

我正在将图像从服务器加载到网格视图中。为此,我正在使用通用图像加载器。我在适配器的 getview() 方法中使用图像加载器。它从 arraylist 获取图像的 URL 并从服务器加载图像。图像可以是 100 的。我在片段中显示网格视图,因此对于每个片段都有一个单独的网格视图。当我长时间在多个片段之间切换时,我不再出现内存不足的错误。

建议的解决方案

    释放未使用的位图。

所以我正在使用第三方库加载图像。我只是在调用函数中传递图像视图,那么如何释放位图?

    在清单中使堆变大

我猜堆内存是动态的,只要内存增加,垃圾收集器就会释放内存。

3.使用UIL/Picasso/Glide避免内存泄漏

4.片段onDestroy()方法()释放内存的代码

private void unbindDrawables(View view)

        if (view.getBackground() != null)
        
                view.getBackground().setCallback(null);
        
        if (view instanceof ViewGroup && !(view instanceof AdapterView))
        
                for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++)
                
                        unbindDrawables(((ViewGroup) view).getChildAt(i));
                
                ((ViewGroup) view).removeAllViews();
        
 

我已经在使用第三方库了。

这是我的 gridViewAdapter 类的代码。

@Override
    public View getView(int position, View convertView, ViewGroup parent) 
        final ViewHolder holder;
        View view = convertView;
        if (view == null)
        
            view = inflater.inflate(R.layout.grid_item_photo, parent, false);
            holder = new ViewHolder();
            holder.imageView = (ImageView) view.findViewById(R.id.imgLoader);
            holder.play = (ImageView) view.findViewById(R.id.play);


            view.setTag(holder);
         
        else 
        
            holder = (ViewHolder) view.getTag();
        
        try
        if(IMAGES_LIST.get(position).getType().equals("video"))
        
        holder.play.setVisibility(View.VISIBLE);
        
         else
        
         holder.play.setVisibility(View.GONE);

         
        ImageLoader.getInstance().displayImage(AppConst.BASE_IMAGE_URL+IMAGES_LIST.get(position).getThumbnail(), holder.imageView, options, new SimpleImageLoadingListener() 
                    @Override
                    public void onLoadingStarted(String imageUri, View view) 
                        view.setClickable(true);
                    

                    @Override
                    public void onLoadingFailed(String imageUri, View view, FailReason failReason) 
                        view.setClickable(true);

                    

                    @Override
                    public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) 
                        view.setClickable(false);

                    
                , new ImageLoadingProgressListener() 
                    @Override
                    public void onProgressUpdate(String imageUri, View view, int current, int total) 

                    
                );
        catch(Exception e)
        

        
        catch(OutOfMemoryError e)
        

        
        return view;
    
    static class ViewHolder 
        ImageView imageView,play;

    


 

【问题讨论】:

您在哪个 android 版本上运行应用程序? @TechGuy andorid kitkat 我听说每个安卓版本的内存管理是不同的。并使用图像缓存来提高性能。 【参考方案1】:

    听起来您的片段泄漏 - 即使调用了 onDestroy,您的片段及其所有内容(包括位图)都保留在内存中。您可以使用 MAT + Heap 转储查看究竟是什么导致了泄漏(那里有很多可用的指南)。第一个嫌疑人应该是您从片段中传递“this”的片段类之外的单例。作为第一步,我会在 onDestroy 中清除您的片段中的所有内容。

    使“SimpleImageLoadingListener()”成为一个内部静态类,将片段保存为 WeakReference - 这可能会减少泄漏(或至少其中一个泄漏)。

    您应该将任何第三个 ImageLoader 用作具有一个 LRU 缓存 + 一个磁盘缓存的 Singleton。你可以在这里找到一些好的 (Any best third party tool to cache image in Android?)

    清单中的“largeHeap”根本不应该出现在您的脑海中。一旦发生泄漏,那么在 OOM 之前,您将需要填满更大的堆。

【讨论】:

【参考方案2】:

你可以删除内存缓存中的缓存图像。为此使用MemoryCacheUtil

MemoryCacheUtils.removeFromCache(imageUrl, imageLoader.getMemoryCache());

DiscCacheUtils 用于删除 discCache

DiscCacheUtils.removeFromCache(url, ImageLoader.getInstance().getDiscCache());

此外,您可以使用以下方法清除内存缓存:

imageLoader.clearMemoryCache();

此外,您可以通过限制来控制内存和磁盘:

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())         
        .memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024)) 
        .discCache(new UnlimitedDiscCache(cacheDir)) 

【讨论】:

为什么会出现这个问题?@jiopez 我没有缓存图像,也没有缓存在磁盘上。 @jlopez 图片动态缓存,避免每次都下载图片 我没有缓存图片。【参考方案3】:

可能是因为你只是通过创建它的实例来使用ImageLoader,而我不知道DisplayImageOptions 你有什么。尝试更改选项设置并检查一下。对我来说这个选项帮我在List中加载大图。

在您的应用中尝试此选项。

DisplayImageOptions imageOptions = new DisplayImageOptions.Builder().showImageForEmptyUri(R.drawable.ic_launcher).showImageOnFail(R.drawable.ic_launcher).resetViewBeforeLoading(true).cacheOnDisk(true).imageScaleType(ImageScaleType.EXACTLY).bitmapConfig(Bitmap.Config.RGB_565).considerExifParams(true).displayer(new FadeInBitmapDisplayer(3000, true, true, false)).build();

【讨论】:

【参考方案4】:

你可以尽量避免内存缓存,限制磁盘缓存。如需进一步优化,您可以查看the source。

【讨论】:

以上是关于如何在android中使用imageloader释放位图内存?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Android 上解释 mobilenetv2 分割结果输出?

Android界面实现关于Android中9patch图的一点小解释

Android界面实现关于Android中9patch图的一点小解释

怎么给代码加注释?

当前Android开发人员如何提升岗位竞争力

JAVA读写XML,加下注释