Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible BUG in Android ImageDownloader class : sHardBitmapCache NOT static when it should be? [closed]

I have been trying to learn as much as possible about Android development with specific focus on performance since many apps in the Play store today are sluggish. I have found/been directed to many articles/videos.

One specific article about image caching is at: http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html

The author has code available at: http://code.google.com/p/android-imagedownloader/source/browse/trunk/src/com/example/android/imagedownloader/ImageDownloader.java

Which Google seemed to take a version of into and put into their sample classes at: http://developer.android.com/resources/samples/XmlAdapters/src/com/example/android/xmladapters/ImageDownloader.html

In general it is solid, except for what I think is a flaw in the caching. It uses a soft / hard cache that puts / gets things into the hard cache because the Android system resets the soft cache quite often.

Looking at the code though, one starts to wonder if the hard cache would get accidentally reset every time the parent class is instantiated.

First the soft cache:

    // Soft cache for bitmaps kicked out of hard cache
    private final static ConcurrentHashMap<String, SoftReference<Bitmap>> sSoftBitmapCache =
        new ConcurrentHashMap<String, SoftReference<Bitmap>>(HARD_CACHE_CAPACITY / 2);

Now take a look at the hard cache:

    // Hard cache, with a fixed maximum capacity and a life duration
    private final HashMap<String, Bitmap> sHardBitmapCache =
        new LinkedHashMap<String, Bitmap>(HARD_CACHE_CAPACITY / 2, 0.75f, true) {
        @Override
        protected boolean removeEldestEntry(LinkedHashMap.Entry<String, Bitmap> eldest) {
            if (size() > HARD_CACHE_CAPACITY) {
                // Entries push-out of hard reference cache are transferred to soft reference cache
                sSoftBitmapCache.put(eldest.getKey(), new SoftReference<Bitmap>(eldest.getValue()));
                return true;
            } else
                return false;
        }
    };

The hard cache is not static, while the soft cache is static. So the hard cache instance and therefore items get cleared with the life of the instance of the class.

The reason I think this is true is that I noticed my application with a ListView/ImageView, was downloading the image every time and never caching it. It was all done asynchronously, but still hitting the net every time. I verified this by putting a Log.d() statement inside my method that hits the web and seeing when/how often it was called.

Adding the static keyword fixed the issue and my application is much more performant.

I am not sure why this is the case as there is only one instance of the ImageDownloader class in my adapter as shown in the example:

private final ImageDownloader imageDownloader = new ImageDownloader();

THE QUESTION

With all of that said, has anyone else experienced this??? Or am I a combination of crazy/wrong somehow. I am no Java/Android/JVM/Dalvik/WeakReference/SoftReference expert, but something seems a bit off. I don't know why sHardBitmapCache was not made static, but when I made the change my application stopped hitting the web so much (saving on data costs / battery drainage / performance improvements).

like image 939
Issa Fram Avatar asked Apr 13 '12 04:04

Issa Fram


1 Answers

You are correct, this is a typo on my part.

I have fixed the code in the android source tree. Thanks for this feedback.

like image 92
Gilles Debunne Avatar answered Oct 19 '22 04:10

Gilles Debunne