Home » Android » Android image caching

Android image caching

Posted by: admin March 10, 2020 Leave a comment

Questions:

How can I cache images after they are downloaded from web?

How to&Answers:

And now the punchline: use the system cache.

URL url = new URL(strUrl);
URLConnection connection = url.openConnection();
connection.setUseCaches(true);
Object response = connection.getContent();
if (response instanceof Bitmap) {
  Bitmap bitmap = (Bitmap)response;
} 

Provides both memory and flash-rom cache, shared with the browser.

grr. I wish somebody had told ME that before i wrote my own cache manager.

Answer:

Regarding the elegant connection.setUseCaches solution above: sadly, it won’t work without some additional effort. You will need to install a ResponseCache using ResponseCache.setDefault. Otherwise, HttpURLConnection will silently ignore the setUseCaches(true) bit.

See the comments at the top of FileResponseCache.java for details:

http://libs-for-android.googlecode.com/svn/reference/com/google/android/filecache/FileResponseCache.html

(I’d post this in a comment, but I apparently don’t have enough SO karma.)

Answer:

Convert them into Bitmaps and then either store them in a Collection(HashMap,List etc.) or you can write them on the SDcard.

When storing them in application space using the first approach, you might want to wrap them around a java.lang.ref.SoftReference specifically if their numbers is large (so that they are garbage collected during crisis). This could ensue a Reload though.

HashMap<String,SoftReference<Bitmap>> imageCache =
        new HashMap<String,SoftReference<Bitmap>>();

writing them on SDcard will not require a Reload; just a user-permission.

Answer:

Use LruCache to cache images efficiently. You can read about LruCache from Android Developer site

I’ve used below solution for Images download and caching in android. You can follow steps below:

STEP 1:
make Class Named ImagesCache. I’ve used Singleton object for this class

import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

public class ImagesCache 
{
    private  LruCache<String, Bitmap> imagesWarehouse;

    private static ImagesCache cache;

    public static ImagesCache getInstance()
    {
        if(cache == null)
        {
            cache = new ImagesCache();
        }

        return cache;
    }

    public void initializeCache()
    {
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() /1024);

        final int cacheSize = maxMemory / 8;

        System.out.println("cache size = "+cacheSize);

        imagesWarehouse = new LruCache<String, Bitmap>(cacheSize)
                {
                    protected int sizeOf(String key, Bitmap value) 
                    {
                        // The cache size will be measured in kilobytes rather than number of items.

                        int bitmapByteCount = value.getRowBytes() * value.getHeight();

                        return bitmapByteCount / 1024;
                    }
                };
    }

    public void addImageToWarehouse(String key, Bitmap value)
    {       
        if(imagesWarehouse != null && imagesWarehouse.get(key) == null)
        {
            imagesWarehouse.put(key, value);
        }
    }

    public Bitmap getImageFromWarehouse(String key)
    {
        if(key != null)
        {
            return imagesWarehouse.get(key);
        }
        else
        {
            return null;
        }
    }

    public void removeImageFromWarehouse(String key)
    {
        imagesWarehouse.remove(key);
    }

    public void clearCache()
    {
        if(imagesWarehouse != null)
        {
            imagesWarehouse.evictAll();
        }       
    }

}

STEP 2:

make another class named DownloadImageTask which is used if bitmap is not available in cache it will download it from here:

public class DownloadImageTask extends AsyncTask<String, Void, Bitmap>
{   
    private int inSampleSize = 0;

    private String imageUrl;

    private BaseAdapter adapter;

    private ImagesCache cache;

    private int desiredWidth, desiredHeight;

    private Bitmap image = null;

    private ImageView ivImageView;

    public DownloadImageTask(BaseAdapter adapter, int desiredWidth, int desiredHeight) 
    {
        this.adapter = adapter;

        this.cache = ImagesCache.getInstance();

        this.desiredWidth = desiredWidth;

        this.desiredHeight = desiredHeight;
    }

    public DownloadImageTask(ImagesCache cache, ImageView ivImageView, int desireWidth, int desireHeight)
    {
        this.cache = cache;

        this.ivImageView = ivImageView;

        this.desiredHeight = desireHeight;

        this.desiredWidth = desireWidth;
    }

    @Override
    protected Bitmap doInBackground(String... params) 
    {
        imageUrl = params[0];

        return getImage(imageUrl);
    }

    @Override
    protected void onPostExecute(Bitmap result) 
    {
        super.onPostExecute(result);

        if(result != null)
        {
            cache.addImageToWarehouse(imageUrl, result);

            if(ivImageView != null)
            {
                ivImageView.setImageBitmap(result);
            }
            else if(adapter != null)
            {
                adapter.notifyDataSetChanged();
            }
        }
    }

    private Bitmap getImage(String imageUrl)
    {   
        if(cache.getImageFromWarehouse(imageUrl) == null)
        {
            BitmapFactory.Options options = new BitmapFactory.Options();

            options.inJustDecodeBounds = true;

            options.inSampleSize = inSampleSize;

            try
            {
                URL url = new URL(imageUrl);

                HttpURLConnection connection = (HttpURLConnection)url.openConnection();

                InputStream stream = connection.getInputStream();

                image = BitmapFactory.decodeStream(stream, null, options);

                int imageWidth = options.outWidth;

                int imageHeight = options.outHeight;

                if(imageWidth > desiredWidth || imageHeight > desiredHeight)
                {   
                    System.out.println("imageWidth:"+imageWidth+", imageHeight:"+imageHeight);

                    inSampleSize = inSampleSize + 2;

                    getImage(imageUrl);
                }
                else
                {   
                    options.inJustDecodeBounds = false;

                    connection = (HttpURLConnection)url.openConnection();

                    stream = connection.getInputStream();

                    image = BitmapFactory.decodeStream(stream, null, options);

                    return image;
                }
            }

            catch(Exception e)
            {
                Log.e("getImage", e.toString());
            }
        }

        return image;
    }

STEP 3: Usage from your Activity or Adapter

Note: If you want to load image from url from Activity Class. Use the second Constructor of DownloadImageTask, but if you want to display image from Adapter use first Constructor of DownloadImageTask (for example you have a image in ListView and you are setting image from ‘Adapter’)

USAGE FROM ACTIVITY:

ImageView imv = (ImageView) findViewById(R.id.imageView);
ImagesCache cache = ImagesCache.getInstance();//Singleton instance handled in ImagesCache class.
cache.initializeCache();

String img = "your_image_url_here";

Bitmap bm = cache.getImageFromWarehouse(img);

if(bm != null)
{
  imv.setImageBitmap(bm);
}
else
{
  imv.setImageBitmap(null);

  DownloadImageTask imgTask = new DownloadImageTask(cache, imv, 300, 300);//Since you are using it from `Activity` call second Constructor.

  imgTask.execute(img);
}

USAGE FROM ADAPTER:

ImageView imv = (ImageView) rowView.findViewById(R.id.imageView);
ImagesCache cache = ImagesCache.getInstance();
cache.initializeCache();

String img = "your_image_url_here";

Bitmap bm = cache.getImageFromWarehouse(img);

if(bm != null)
{
  imv.setImageBitmap(bm);
}
else
{
  imv.setImageBitmap(null);

  DownloadImageTask imgTask = new DownloadImageTask(this, 300, 300);//Since you are using it from `Adapter` call first Constructor.

  imgTask.execute(img);
}

Note:

cache.initializeCache() you can use this statement in the very first Activity of your application. Once you’ve initialized the cache you would never need to initialized it every time if you are using ImagesCache instance.

I am never good at explaining things but hope this will help the beginners that how to cache using LruCache and its usage 🙂

EDIT:

Now a days there are very famous libraries known as Picasso and Glide which can be used to load images very efficiently in android app. Try this very simple and usefull library Picasso for android and Glide For Android. You do not need to worry about cache images.

Picasso allows for hassle-free image loading in your application—often
in one line of code!

Glide, just like Picasso, can load and display images from many
sources, while also taking care of caching and keeping a low memory
impact when doing image manipulations. It has been used by official
Google apps (like the app for Google I/O 2015) and is just as popular
as Picasso. In this series, we’re going to explore the differences and
advantages of Glide over Picasso.

You can also visit blog for difference between Glide and Picasso

Answer:

To download an image and save to the memory card you can do it like this.

//First create a new URL object 
URL url = new URL("http://www.google.co.uk/logos/holiday09_2.gif")

//Next create a file, the example below will save to the SDCARD using JPEG format
File file = new File("/sdcard/example.jpg");

//Next create a Bitmap object and download the image to bitmap
Bitmap bitmap = BitmapFactory.decodeStream(url.openStream());

//Finally compress the bitmap, saving to the file previously created
bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream(file));

Don’t forget to add the Internet permission to your manifest:

<uses-permission android:name="android.permission.INTERNET" />

Answer:

I would consider using droidfu’s image cache. It implements both an in-memory and disk-based image cache. You also get a WebImageView that takes advantage of the ImageCache library.

Here is the full description of droidfu and WebImageView:
http://brainflush.wordpress.com/2009/11/23/droid-fu-part-2-webimageview-and-webgalleryadapter/

Answer:

I’ve tried SoftReferences, they are too aggressively reclaimed in android that I felt there was no point using them

Answer:

As Thunder Rabbit suggested, ImageDownloader is the best one for the job. I also found a slight variation of the class at:

http://theandroidcoder.com/utilities/android-image-download-and-caching/

The main difference between the two is that the ImageDownloader uses the Android caching system, and the modified one uses internal and external storage as caching, keeping the cached images indefinitely or until the user removes it manually. The author also mentions Android 2.1 compatibility.

Answer:

This is a good catch by Joe. The code example above has two problems – one – the response object isn’t an instance of Bitmap (when my URL references a jpg, like http:\website.com\image.jpg, its a

org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl$LimitedInputStream).

Second, as Joe points out, no caching occurs without a response cache being configured. Android developers are left to roll their own cache. Here’s an example for doing so, but it only caches in memory, which really isn’t the full solution.

http://codebycoffee.com/2010/06/29/using-responsecache-in-an-android-app/

The URLConnection caching API is described here:

http://download.oracle.com/javase/6/docs/technotes/guides/net/http-cache.html

I still think this is an OK solution to go this route – but you still have to write a cache. Sounds like fun, but I’d rather write features.

Answer:

There is a special entry on the official training section of Android about this: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html

The section is quite new, it was not there when the question was asked.

The suggested solution is to use a LruCache. That class was introduced on Honeycomb, but it is also included on the compatibility library.

You can initialize a LruCache by setting the maximum number or entries and it will automatically sort them your you and clean them less used ones when you go over the limit. Other than that it is used as a normal Map.

The sample code from the official page:

private LruCache mMemoryCache;

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    // Get memory class of this device, exceeding this amount will throw an
    // OutOfMemory exception.
    final int memClass = ((ActivityManager) context.getSystemService(
            Context.ACTIVITY_SERVICE)).getMemoryClass();

    // Use 1/8th of the available memory for this memory cache.
    final int cacheSize = 1024 * 1024 * memClass / 8;

    mMemoryCache = new LruCache(cacheSize) {
        @Override
        protected int sizeOf(String key, Bitmap bitmap) {
            // The cache size will be measured in bytes rather than number of items.
            return bitmap.getByteCount();
        }
    };
    ...
}

public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
    if (getBitmapFromMemCache(key) == null) {
        mMemoryCache.put(key, bitmap);
    }
}

public Bitmap getBitmapFromMemCache(String key) {
    return mMemoryCache.get(key);
}

Previously SoftReferences were a good alternative, but not anymore, quoting from the official page:

Note: In the past, a popular memory cache implementation was a
SoftReference or WeakReference bitmap cache, however this is not
recommended. Starting from Android 2.3 (API Level 9) the garbage
collector is more aggressive with collecting soft/weak references
which makes them fairly ineffective. In addition, prior to Android 3.0
(API Level 11), the backing data of a bitmap was stored in native
memory which is not released in a predictable manner, potentially
causing an application to briefly exceed its memory limits and crash.

Answer:

Consider using Universal Image Loader library by Sergey Tarasevich. It comes with:

  • Multithread image loading. It lets you can define the thread pool size
  • Image caching in memory, on device’s file sytem and SD card.
  • Possibility to listen to loading progress and loading events

Universal Image Loader allows detailed cache management for downloaded images, with the following cache configurations:

  • UsingFreqLimitedMemoryCache: The least frequently used bitmap is deleted when the cache size limit is exceeded.
  • LRULimitedMemoryCache: The least recently used bitmap is deleted when the cache size limit is exceeded.
  • FIFOLimitedMemoryCache: The FIFO rule is used for deletion when the cache size limit is exceeded.
  • LargestLimitedMemoryCache: The largest bitmap is deleted when the cache size limit is exceeded.
  • LimitedAgeMemoryCache: The Cached object is deleted when its age exceeds defined value.
  • WeakMemoryCache: A memory cache with only weak references to bitmaps.

A simple usage example:

ImageView imageView = groupView.findViewById(R.id.imageView);
String imageUrl = "http://site.com/image.png"; 

ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.init(ImageLoaderConfiguration.createDefault(context));
imageLoader.displayImage(imageUrl, imageView);

This example uses the default UsingFreqLimitedMemoryCache.

Answer:

What actually worked for me was setting ResponseCache on my Main class:

try {
   File httpCacheDir = new File(getApplicationContext().getCacheDir(), "http");
   long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
   HttpResponseCache.install(httpCacheDir, httpCacheSize);
} catch (IOException e) { } 

and

connection.setUseCaches(true);

when downloading bitmap.

http://practicaldroid.blogspot.com/2013/01/utilizing-http-response-cache.html

Answer:

Google’s libs-for-android has a nice libraries for managing image and file cache.

http://code.google.com/p/libs-for-android/

Answer:

I had been wrestling with this for some time; the answers using SoftReferences would lose their data too quickly. The answers that suggest instantiating a RequestCache were too messy, plus I could never find a full example.

But ImageDownloader.java works wonderfully for me. It uses a HashMap until the capacity is reached or until the purge timeout occurs, then things get moved to a SoftReference, thereby using the best of both worlds.

Answer:

I suggest IGNITION this is even better than Droid fu

https://github.com/kaeppler/ignition

https://github.com/kaeppler/ignition/wiki/Sample-applications

Answer:

Even later answer, but I wrote an Android Image Manager that handles caching transparently (memory and disk). The code is on Github https://github.com/felipecsl/Android-ImageManager

Answer:

Late answer, but I figured I should add a link to my site because I have written a tutorial how to make an image cache for android: http://squarewolf.nl/2010/11/android-image-cache/ Update: the page has been taken offline as the source was outdated. I join @elenasys in her advice to use Ignition.

So to all the people who stumble upon this question and haven’t found a solution: hope you enjoy! =D

Answer:

Late answer but I think this library will help a lot with caching images :
https://github.com/crypticminds/ColdStorage.

Simply annotate the ImageView with
@LoadCache(R.id.id_of_my_image_view, “URL_to_downlaod_image_from) and it will take care of downloading the image and loading it into the image view. You can also specify a placeholder image and loading animation.

Detailed documentation of the annotation is present here :-
https://github.com/crypticminds/ColdStorage/wiki/@LoadImage-annotation