I need help understanding androids LruCache. I want to use to load images into my gridview in order make the loading/scrolling better. Can someone post an example code using LruCache please. Thanks in advance.
android.util.LruCache<K, V> A cache that holds strong references to a limited number of values. Each time a value is accessed, it is moved to the head of a queue. When a value is added to a full cache, the value at the end of that queue is evicted and may become eligible for garbage collection.
The Least Recently Used (LRU) cache is a cache eviction algorithm that organizes elements in order of use. In LRU, as the name suggests, the element that hasn't been used for the longest time will be evicted from the cache.
LRU (Least Recently Used) Cache discards the least recently used items first. This algorithm requires keeping track of what was used when, which is expensive if one wants to make sure the algorithm always discards the least recently used item.
Below is a class I made for using LruCache, this is based on the presentation Doing More With Less: Being a Good Android Citizen given at Google I/O 2012.
Check out the movie for more information about what I'm doing in the TCImageLoader
class:
public class TCImageLoader implements ComponentCallbacks2 { private TCLruCache cache; public TCImageLoader(Context context) { ActivityManager am = (ActivityManager) context.getSystemService( Context.ACTIVITY_SERVICE); int maxKb = am.getMemoryClass() * 1024; int limitKb = maxKb / 8; // 1/8th of total ram cache = new TCLruCache(limitKb); } public void display(String url, ImageView imageview, int defaultresource) { imageview.setImageResource(defaultresource); Bitmap image = cache.get(url); if (image != null) { imageview.setImageBitmap(image); } else { new SetImageTask(imageview).execute(url); } } private class TCLruCache extends LruCache<String, Bitmap> { public TCLruCache(int maxSize) { super(maxSize); } @Override protected int sizeOf(ImagePoolKey key, Bitmap value) { int kbOfBitmap = value.getByteCount() / 1024; return kbOfBitmap; } } private class SetImageTask extends AsyncTask<String, Void, Integer> { private ImageView imageview; private Bitmap bmp; public SetImageTask(ImageView imageview) { this.imageview = imageview; } @Override protected Integer doInBackground(String... params) { String url = params[0]; try { bmp = getBitmapFromURL(url); if (bmp != null) { cache.put(url, bmp); } else { return 0; } } catch (Exception e) { e.printStackTrace(); return 0; } return 1; } @Override protected void onPostExecute(Integer result) { if (result == 1) { imageview.setImageBitmap(bmp); } super.onPostExecute(result); } private Bitmap getBitmapFromURL(String src) { try { URL url = new URL(src); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoInput(true); connection.connect(); InputStream input = connection.getInputStream(); Bitmap myBitmap = BitmapFactory.decodeStream(input); return myBitmap; } catch (IOException e) { e.printStackTrace(); return null; } } } @Override public void onConfigurationChanged(Configuration newConfig) { } @Override public void onLowMemory() { } @Override public void onTrimMemory(int level) { if (level >= TRIM_MEMORY_MODERATE) { cache.evictAll(); } else if (level >= TRIM_MEMORY_BACKGROUND) { cache.trimToSize(cache.size() / 2); } } }
I've found a really easy way that work perfectly for me...
This is the Cache.java class. In this class, the static getInstance()
method enables us to create only one cache instance in the whole application. getLru()
method is used to retrieve the cached object, it will be shown later how to use it. This cache is generic, meaning you can save any Object type into it. The cache memory size here is set to 1024. It can be changed if it is too small:
import android.support.v4.util.LruCache; public class Cache { private static Cache instance; private LruCache<Object, Object> lru; private Cache() { lru = new LruCache<Object, Object>(1024); } public static Cache getInstance() { if (instance == null) { instance = new Cache(); } return instance; } public LruCache<Object, Object> getLru() { return lru; } }
This is the code in your activity where you save the bitmap to the cache:
public void saveBitmapToCahche(){ //The imageView that you want to save it's bitmap image resourse ImageView imageView = (ImageView) findViewById(R.id.imageViewID); //To get the bitmap from the imageView Bitmap bitmap = ((BitmapDrawable)imageview.getDrawable()).getBitmap(); //Saving bitmap to cache. it will later be retrieved using the bitmap_image key Cache.getInstance().getLru().put("bitmap_image", bitmap); }
This is the code where you retrieve the bitmap from the cache, then set an imageView to this bitmap:
public void retrieveBitmapFromCache(){ //The imageView that you want to set to the retrieved bitmap ImageView imageView = (ImageView) findViewById(R.id.imageViewID); //To get bitmap from cache using the key. Must cast retrieved cache Object to Bitmap Bitmap bitmap = (Bitmap)Cache.getInstance().getLru().get("bitmap_image"); //Setting imageView to retrieved bitmap from cache imageView.setImageBitmap(bitmap)); }
THAT'S ALL! As you can see this is rather easy and simple.
In my application, All the views are saved in class variables so they can be seen by all the methods in the class. In my first activity, I save the image bitmap to the cache in an onClickButton()
method, right before I start a new activity using intent. I also save a string value in my cache:
public void onClickButton(View v){ Bitmap bitmap = ((BitmapDrawable)imageView.getDrawable()).getBitmap(); String name = textEdit.getText().toString(); Cache.getInstance().getLru().put("bitmap_image", bitmap); Cache.getInstance().getLru().put("name", name); Intent i = new Intent(FirstActivity.this, SecondActivity.class); startActivity(i); }
Then I navigate from the second activity to a third activity also using intents. In the last activity I save other objects into my cache, then go back to the first activity using an intent. Once I'm back in the first activity, the onCreate()
method will start. In that method, I check if my cache has any bitmap value or any String value separately (based on my application business):
public ImageView imageView; public EditText editText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_first); //...Other code... //The imageView that you want to save it's bitmap image resourse imageView = (ImageView) findViewById(R.id.imageViewID); //The editText that I want to save it's text into cache editText = (EditText)findViewById(R.id.editTextID); if(Cache.getInstance().getLru().get("name")!=null){ editText.setText(Cache.getInstance().getLru().get("name").toString()); } if(Cache.getInstance().getLru().get("bitmap_image")!=null){ imageView.setImageBitmap((Bitmap)Cache.getInstance().getLru().get("bitmap_image")); } //...Other code... }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With