1

In my Android app, I am using a custom ImageView class (Banner) to display images pulled from Facebook Events. While running the app, I notice that there is a large heap size (120 MB) while running the app. I used MAT and I think I've narrowed it down to byte[] and then finally to ImageView. Please check the pictures below to see how I came to this conclusion.

enter image description here enter image description here enter image description here

Now, I've read similar posts and I tried recycling my bitmap, using WeakReferences, creating a cache, but nothing seems to be reducing the memory size. However, recycling my bitmap threw me an error which said that I can't use a recycled bitmap (I feel like that may be a hint because it's keeping my bitmap in memory?).

The app isn't running slowly on my phone (It even only says a CPU usage of 1.5% even though the memory is on average 100 MB). I will post my Banner subclass and how I download the images to see if anyone can help me.

Banner.java:

public class Banner extends ImageView {
    public Banner(Context context) {
        super(context);
    }

    public Banner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public Banner(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = 400;
        if (getDrawable() != null && getDrawable().getIntrinsicWidth() != 0){
            height = width * getDrawable().getIntrinsicHeight() / getDrawable().getIntrinsicWidth();
            if (height < 500)
                height = 700;
        }
        setMeasuredDimension(width, height);
        setColorFilter(Color.rgb(123, 123, 123), android.graphics.PorterDuff.Mode.MULTIPLY);
    }
    public void onDestroy(){
        Drawable drawable = this.getDrawable();
        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
            Bitmap bitmap = bitmapDrawable.getBitmap();
            bitmap.recycle();
        }
        this.setImageBitmap(null);
    }
}

BannerLoader.java:

public class BannerLoader{
    private String url;
    private WeakReference<ImageView> cover;
    private LruCache<String, WeakReference<Bitmap>> mMemoryCache;
    final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
    final int cacheSize = maxMemory / 8;
    public BannerLoader(String cover_url, WeakReference<ImageView> cover, Drawable defaultDrawable) {
        this.url = cover_url;
        this.cover = cover;
        cover.get().setBackground(defaultDrawable);
        mMemoryCache = new LruCache<String, WeakReference<Bitmap>>(cacheSize) {
            @Override
            protected int sizeOf(String key, WeakReference<Bitmap> bitmap) {
                // The cache size will be measured in kilobytes rather than
                // number of items.
                return bitmap.get().getByteCount() / 1024;
            }
        };
        new DownloadImage().execute();
    }
    public void addBitmapToMemoryCache(String key, WeakReference<Bitmap> bitmap) {
        if (getBitmapFromMemCache(key) == null) {
            mMemoryCache.put(key, bitmap);
        }
    }
    public WeakReference<Bitmap> getBitmapFromMemCache(String key) {
        return mMemoryCache.get(key);
    }
    class DownloadImage extends AsyncTask<Void, Void, WeakReference<Bitmap>>{
        protected WeakReference<Bitmap> doInBackground(Void... params){
            try {
                final WeakReference<Bitmap> cachedBitmap = getBitmapFromMemCache(url);
                if (cachedBitmap != null){
                    return cachedBitmap;
                } else{
                    URL pictureURL = new URL(url);
                    HttpGet httpRequest = null;

                    httpRequest = new HttpGet(pictureURL.toURI());

                    HttpClient httpclient = new DefaultHttpClient();
                    HttpResponse response = (HttpResponse) httpclient
                            .execute(httpRequest);

                    HttpEntity entity = response.getEntity();
                    BufferedHttpEntity b_entity = new BufferedHttpEntity(entity);
                    InputStream input = b_entity.getContent();

                    WeakReference<Bitmap> bitmap = new WeakReference<Bitmap>(BitmapFactory.decodeStream(input));
                    addBitmapToMemoryCache(url, bitmap);
                    return bitmap;
                }
            } catch(Exception ex){
                ex.printStackTrace();
            }
            return null;
        }
        public void onPostExecute(WeakReference<Bitmap> image){
            if (image != null && cover.get() != null){
                cover.get().setImageBitmap(image.get());
            }
        }
    }
}

So, as an example, I download an image like this:

new BannerLoader(tempEvent.getCover_url(), new WeakReference<ImageView>(thumb_image), context.getResources().getDrawable(R.drawable.placeholder));

Thanks for the help!

Community
  • 1
  • 1
sameetandpotatoes
  • 1,220
  • 3
  • 17
  • 35
  • I was hoping someone would have commented on this - I wanted to see the answer. Have you got any nearer? – Rob Aug 08 '14 at 07:53
  • Not really. My list view has gotten even larger since this, and I am at 150 mb with visible out of memory errors. One compromise I had to fix was to rewrite my custom adapters getview method to reuse views and use the viewholder, but this was causing my list view to get out of order. To fix, I removed the two types of objects in my list view and made it one object, which cut memory by 30 mb. So no more out of memory, but still slow. – sameetandpotatoes Aug 08 '14 at 14:08
  • I have a feeling its not even bitmaps as when I open the android app at the login page the memory is at 70 mb. – sameetandpotatoes Aug 08 '14 at 14:09
  • Any solution? This is similar to https://stackoverflow.com/questions/31839580/extending-imageview-causes-memory-leak – Pablo Alfonso May 20 '20 at 12:33

0 Answers0