Add LRUCache cache to your app to easily solve an oom caused by too many pictures

Source: Internet
Author: User

The last time I had a phone interview asking about the caching strategy in Android, the vague answer is now a good reason.

The cache policy that is normally taken in Android is to use level two caching. That is, memory cache + hard disk cache->lrucache+disklrucache. Second-level cache to meet most of the requirements, there is also a level three cache (memory cache + hard disk cache + network cache), in which Disklrucache is the hard disk cache, the next part of the story!

1. What exactly is LRUCache?

Checked the official information. This is defined as:

LruCache is a cache that holds strong references to a limited number of cached objects, and each time a cached object is interviewed, it is moved to the head of the queue. When an object is added to a LruCache that has reached the limit, the object at the end of the queue is removed and may be reclaimed by the garbage collector. LruCache? The Lru in is referred to as "Least recently used-least recently used algorithm".

This means that LruCache is a cache object that can infer which cache object is the least recently used. This moves the fewest use to the end of the queue, while the most recently used is left in front of the queues. For example: We have a, B, C, D, e Five elements, and a, C, D, E have been interviewed. Only the B element is not visited, then the B element becomes the least recently used element and moves to the end of the team.

From the above narrative we conclude that we can know the core idea of LRUCache two points:

1. LRUCache uses the least recently used algorithm. The least recently used will be moved to the end of the team. The most recently used move to the head.

2. The size of the LRUCache cache is limited (defined by us), and when the LRUCache storage space is full it removes the tail of the queue and frees the controls for new objects.

2, we still learn from the source code LRUCache how to use it:

Let's start by looking at what the variables in the LRUCache class have:


Displays variables that find a heap of type int. Another most important linkedhashmap<k,v> this queue, the popular linkedhashmap<k,v> is a two-way linked list storage structure.

The meaning of each variable is:

The size already stored in the Size-lrucache

MaxSize-The maximum space we define for the LRUCache cache

Number of Putcount-put (number of Cache objects added to LRUCache)

Number of Createcount-create

Evictioncount-Number of recoveries

HitCount-Number of hits

Misscount-Number of Lost

Then look at the constructor:

Public LruCache (int maxSize) {        if (maxSize <= 0) {            throw new IllegalArgumentException ("maxSize <= 0");        }        this.maxsize = maxSize;        This.map = new linkedhashmap<k, v> (0, 0.75f, true);    }
A value that is required to pass in an int type is found. Name implies. This is the size of the LRUCache cache we have defined, and in general we can get the maximum free space for the application and then set it to a percentage value.

And look at some other important ways:

Put () Method:

Public final V put (K key, V value) {        if (key = = NULL | | value = = NULL) {            throw new NullPointerException ("key = = Nu ll | | Value = = null ");        }        V previous;        Synchronized (this) {            putcount++;            Size + = safesizeof (key, value);            Previous = Map.put (key, value);            if (previous! = null) {                Size-= safesizeof (key, previous);}        }        if (previous! = null) {            entryremoved (false, key, previous, value);        }        TrimToSize (maxSize);        return previous;    }
By this method we can know that the cache data is stored in the LRUCache in the form of <Key,Value>.

This means that we store a value in LRUCache and set the corresponding key value to key. Then it is inferred that both key and value cannot be empty, otherwise it throws an exception. The value is then moved to the head of the queue.

Get () Method:

    Public final V get (K key) {if (key = = null) {throw new NullPointerException ("key = = null");        } V Mapvalue;            Synchronized (this) {Mapvalue = Map.get (key);                if (mapvalue! = null) {hitcount++;            return mapvalue;        } misscount++; }/* * Attempt to create a value. This is a long time, and the map * May is different when create () returns.  If a conflicting value is * added to the map while create () is working, we leave that value in * the map         and release the created value.        */V Createdvalue = Create (key);        if (Createdvalue = = null) {return null;            } synchronized (this) {createcount++;            Mapvalue = Map.put (key, Createdvalue); if (mapvalue! = null) {//There is a conflict so undo the last put Map.put (key, Mapvalue)      ;      } else {size + safesizeof (key, Createdvalue);            }} if (Mapvalue! = null) {entryremoved (False, Key, Createdvalue, Mapvalue);        return mapvalue;            } else {trimtosize (maxSize);        return createdvalue; }    }
The method is to get the value of the corresponding key cache, if the value exists, return value and move to the value to the head of the queue, which confirms that the most recently used will be moved to the head of the queue.

Returns null if value does not exist.

Remove () Method:

    Public final V Remove (K key) {        if (key = = null) {            throw new NullPointerException ("key = = null");        }        V previous;        Synchronized (this) {            previous = Map.Remove (key);            if (previous! = null) {                Size-= safesizeof (key, previous);}        }        if (previous! = null) {            entryremoved (false, key, previous, NULL);        }        return previous;    }
The method is to remove the value of the corresponding key from the LRUCache cache.

sizeof () Method: General need to rewrite:

protected int sizeOf (K key, V value) {        return 1;    }
Override it to calculate the size of different value.

In general, we will rewrite this:

Mlrucache = new lrucache<string, bitmap> (cacheSize) {            @Override            protected int sizeOf (String key, Bitmap Bitmap) {                if (bitmap!=null) {                    return bitmap.getbytecount ();                }                return 0;            }        };

Well, let's summarize the principle of using LRUCache: for example, when a picture is loaded in a imageview, it first checks the LRUCache cache for a corresponding key value (get (key)) and returns the corresponding bitmap. To update the ImageView. Suppose that there is not yet another asynchronous thread that loads this picture again.

Take a look at the sample with LRUCache cache bitmap:

public class Mylrucache extends appcompatactivity{private lrucache<string,bitmap> mlrucache;        @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);        Get the application maximum available memory int maxCache = (int) runtime.getruntime (). MaxMemory ();            int cacheSize = maxcache/8;//Set the picture cache size to the total application memory of 1/8 Mlrucache = new lrucache<string, bitmap> (cacheSize) {                    @Override protected int sizeOf (String key, Bitmap Bitmap) {if (bitmap!=null) {                return Bitmap.getbytecount ();            } return 0;    }        }; }/** * Add bitmap to LRUCache * * @param key * @param bitmap */public void Putbitmaptolrucache (STR        ing key, Bitmap Bitmap) {if (Getbitmapfromlrucache (key) = = null) {Mlrucache.put (key, Bitmap); }}/** * @param key * @return get a bitmap from the LRUCache cache. None will return NULL */public BITMAP Getbitmapfromlrucache (String key) {return mlrucache.get (key); }}
Here's an example to see how to use:

Let's look at the effect first:




Paste the main code:

Mainactivity:

public class Mainactivity extends Actionbaractivity {private GridView mgridview;    Private list<string> datas;    Private Toolbar Mtoolbar;    Private Gridviewadapter Madapter;        @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);        Setcontentview (R.layout.activity_main);        LOG.V ("Zxy", "cache:" + getcachedir (). GetPath ());        LOG.V ("Zxy", "Excache:" + getexternalcachedir (). GetPath ());        Mtoolbar = (Toolbar) Findviewbyid (R.id.toolbar);        Mtoolbar.settitletextcolor (Color.White);        Mtoolbar.setnavigationicon (R.mipmap.icon);        Setsupportactionbar (Mtoolbar);        Initdatas ();        Mgridview = (GridView) Findviewbyid (R.id.gridview);        Madapter = new Gridviewadapter (this, Mgridview, datas);        Mgridview.setadapter (Madapter); Mgridview.setonitemclicklistener (New Adapterview.onitemclicklistener () {@Override public void Onite Mclick (adapterview<?> Parent, view view, int position, long id) {Toast.maketext (mainactivity.this, "position=" + position + ", I            D= "+ ID, toast.length_short). Show ();    }        });        } public void Initdatas () {datas = new arraylist<> ();        for (int i = 0; i <; i++) {Datas.add (urldatastools.imageurls[i]);        }} @Override protected void OnDestroy () {Super.ondestroy (); Madapter.cancelalldownloadtask ();//Cancel all download Tasks}}


Gridviewadapter:

public class Gridviewadapter extends Baseadapter implements Abslistview.onscrolllistener {private List<downloadtask    > mdownloadtasklist;//all Download the collection of asynchronous threads private Context Mcontext;    Private GridView Mgridview;    Private list<string> datas;    Private lrucache<string, bitmap> Mlrucache; private int mfirstvisibleitem;//The current page displays the position of the first item position private int mvisibleitemcount;//The current page shows how many item private bool    Ean isfirstrunning = true;        Public Gridviewadapter (context context, GridView Mgridview, list<string> datas) {this.mcontext = context;        This.datas = datas;        This.mgridview = Mgridview;        This.mGridView.setOnScrollListener (this);        Mdownloadtasklist = new arraylist<> ();    Initcache ();        } private void Initcache () {//Gets the application's maximum available memory int maxCache = (int) runtime.getruntime (). MaxMemory (); int cacheSize = maxcache/8;//Sets the picture cache size to the total application memory of 1/8 Mlrucache = new lrucache<string, bitmap> (cAchesize) {@Override protected int sizeOf (String key, Bitmap Bitmap) {if (Bitmap! =                NULL) {return bitmap.getbytecount ();            } return 0;    }        };    } @Override public int getcount () {return datas.size ();    } @Override public Object getItem (int position) {return datas.get (position);    } @Override public long getitemid (int position) {return position; } @Override public View getView (int position, view Convertview, ViewGroup parent) {Convertview = Layoutinfla        Ter.from (Mcontext). Inflate (R.layout.layout_item, parent, false);        ImageView Mimageview = (ImageView) Convertview.findviewbyid (R.id.imageview);        TextView Mtextview = (TextView) Convertview.findviewbyid (R.id.textview);        String url = datas.get (position); Mimageview.settag (String2md5tools.hashkeyfordisk (URL)), or//set a tag MD5 (URL), to ensure that the picture is good to display mtextview.seTtext ("first" + Position + "item");        Setimageviewforbitmap (Mimageview, URL);    return convertview; }/** * to ImageView settings bitmap * * @param imageView * @param URL */private void SETIMAGEVIEWFORBITM AP (ImageView ImageView, string url) {string key = String2md5tools.hashkeyfordisk (URL);//MD5 encoding of the URL Bitmap        Bitmap = Getbitmapfromlrucache (key); if (bitmap! = null) {//is assumed to exist in the cache.        Then set the bitmap Imageview.setimagebitmap (bitmap) in the cache;        } else {//does not exist to set a default background color Imageview.setbackgroundresource (r.color.color_five); }}/** * add bitmap to LRUCache * * @param key * @param bitmap */public void Putbitmaptolrucach        E (String key, Bitmap Bitmap) {if (Getbitmapfromlrucache (key) = = null) {Mlrucache.put (key, Bitmap); }}/** * @param key * @return get a Bitmap from the LRUCache cache, none will return NULL */public Bitmap GETBITMAPFROML  Rucache (String key) {      return Mlrucache.get (key); } @Override public void onscrollstatechanged (Abslistview view, int scrollstate) {if (scrollstate = = scroll_s        Tate_idle) {//gridview is a smart state, let it download pictures LoadBitmap (Mfirstvisibleitem, Mvisibleitemcount);        } else {//scroll to cancel all download Tasks Cancelalldownloadtask (); }} @Override public void onscroll (Abslistview view, int firstvisibleitem, int visibleitemcount, int totalitemcou        NT) {mfirstvisibleitem = Firstvisibleitem;        Mvisibleitemcount = VisibleItemCount; if (isfirstrunning && visibleitemcount > 0) {//Load picture on first entry LoadBitmap (Mfirstvisibleitem, MVISIBLEITEMC            Ount);        Isfirstrunning = false; }}/** * load picture into ImageView * * @param mfirstvisibleitem * @param mvisibleitemcount */Private void LoadBitmap (int mfirstvisibleitem, int mvisibleitemcount) {//First infer that the picture is not in the cache, assuming that the asynchronous thread is not opened to download the picture for (int i = Mfirstvisibleitem; I < Mfirstvisibleitem + Mvisibleitemcount;            i++) {final String url = datas.get (i);            String key = String2md5tools.hashkeyfordisk (URL);            Bitmap Bitmap = Getbitmapfromlrucache (key); If the picture is present in the {////cache bitmap = null), it is set to ImageView ImageView Mimageview = (ImageView) mgridview                . Findviewwithtag (String2md5tools.hashkeyfordisk (URL));                if (Mimageview! = null) {Mimageview.setimagebitmap (bitmap);                }} else {//does not exist, open an asynchronous thread to download Downloadtask task = new Downloadtask ();            Mdownloadtasklist.add (Task);//Add the download task to the Download Collection Task.execute (URL);        }}} class Downloadtask extends Asynctask<string, Void, bitmap> {String URL;            @Override protected Bitmap doinbackground (String ... params) {//download image URL in background = params[0]; Bitmap Bitmap = DownloadbitmAP (URL);                 if (bitmap! = null) {//Put the downloaded picture in LRUCache String key = String2md5tools.hashkeyfordisk (URL);            Putbitmaptolrucache (key, bitmap);        } return bitmap;            } @Override protected void OnPostExecute (Bitmap Bitmap) {super.onpostexecute (BITMAP); Show the downloaded picture ImageView Mimageview = (ImageView) mgridview.findviewwithtag (String2md5tools.hashkeyfordisk (URL            ));                if (Mimageview! = null && bitmap! = null) {Mimageview.setimagebitmap (bitmap);    Mdownloadtasklist.remove (this);//Remove the downloaded task}}/** * @param tasks * Cancel all download Tasks * * public void Cancelalldownloadtask () {if (mdownloadtasklist!=null) {for (int i = 0; i < Mdownloadtaskli St.size ();            i++) {mdownloadtasklist.get (i). Cancel (true); }}}/** * Create a Web link download image * * @param uRLSTR * @return * * * Private Bitmap Downloadbitmap (String urlstr) {httpurlconnection connection = null;        Bitmap Bitmap = null;            try {URL url = new URL (urlstr);            Connection = (httpurlconnection) url.openconnection ();            Connection.setconnecttimeout (5000);            Connection.setreadtimeout (5000);            Connection.setdoinput (TRUE);            Connection.connect (); if (connection.getresponsecode () = = HTTPURLCONNECTION.HTTP_OK) {InputStream Minputstream = Connection.geti                Nputstream ();            Bitmap = Bitmapfactory.decodestream (Minputstream);        }} catch (Malformedurlexception e) {e.printstacktrace ();        } catch (IOException e) {e.printstacktrace ();            } finally {if (connection! = null) {connection.disconnect ();    }} return bitmap; }}

All right. LRUCache introduced to this. in the above example there is a problem is not to do a picture size check, too large picture is not compressed.

Next article to introduce how to compress the big picture!!!

Source code Address: http://download.csdn.net/detail/u010687392/8920169







Add LRUCache cache to your app to easily solve an oom caused by too many pictures

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.