Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to release memory of bitmap using imageloader in android?

I am loading images into a grid view from a server. For this, I'm using Universal Image loader. I am using the image loader inside the getview() method of the adapter. It takes the URL of the image from arraylist & loads the image from server. Images can be in 100's. I am displaying the grid view in a fragment so for each fragment there is a separate grid view. When I switch between multiple fragments for a long time I no longer get the out of memory error.

Suggested solution:

  1. Release the unused bitmap.

So I am loading the images using third party library. I am just passing the image view in the calling function so how can I release the bitmap?

  1. Make heap large true in manifest

I guess heap memory is dynamic & whenever there is an increase in memory garbage collector will free the memory.

3.Use UIL/Picasso/Glide to avoid memory leaks

4.Code to release the memory of fragment onDestroy() method ()

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();
        }
} 

I am already using a third party library.

Here is the code for my gridViewAdapter class.

@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;

    }


} 
like image 747
TechChain Avatar asked Jul 10 '15 13:07

TechChain


3 Answers

  1. It sounds like your fragments leak - your fragment stays in memory with all their content (including the bitmap) even if onDestroy is called. You can use MAT + Heap dumps the see what exactly causes the leak (there are many guides available out there). The first suspects should be Singletons of out of fragment classes that you pass "this" from your fragments. As the first step I would clear everything from your fragment in onDestroy.

  2. Make the "SimpleImageLoadingListener()" an inner static class that holds your fragment as WeakReference - this will probably reduce the leak (or at least one of them).

  3. You should be using any 3rd ImageLoader as a Singleton with one LRU cache + one disk cache. You can find some good ones here (Any best third party tool to cache image in Android?)

  4. "largeHeap" in the manifest shouldn't be on your mind at all. Once you have a leak then you'll just have a larger heap to fill up until OOM.

like image 150
MarkySmarky Avatar answered Nov 20 '22 16:11

MarkySmarky


Yo can delete cached image in memory cache. Use MemoryCacheUtil for that:

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

And DiscCacheUtils for delete discCache

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

Besides, you can Clear Memory Cache using:

imageLoader.clearMemoryCache();

Also, you can control the memory and disk with limits:

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())         
        .memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024)) 
        .discCache(new UnlimitedDiscCache(cacheDir)) 
like image 20
jlopez Avatar answered Oct 20 '22 01:10

jlopez


You can try to avoid memory cache, and limit disk cache. For further optimisations you can check the source.

like image 1
yahya Avatar answered Nov 20 '22 18:11

yahya