Add the 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 was, now let's take a good look at it.

In general, the caching strategy in Android is to use level two cache, memory cache + hard disk cache->lrucache+disklrucache, level two cache to meet most requirements, and a three level cache (memory cache + hard disk cache + network cache). Where Disklrucache is the hard disk cache, the next part of the story!

1. So what is LRUCache?

Check the official information, it is defined as:

LruCache is a cache that holds strong references to a limited number of cached objects, and each time the cached object is accessed, 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. The Lru in LruCache refers to the "Least recently used-least recently used algorithm". This means that LruCache is a cache object that is able to determine which cache object is the least recently used, thus moving the fewest used to the end of the queue, while the recent ones are left in front of the queues. For example: We have a, B, C, D, e Five elements, and a, C, D, e have been visited, only the B element is not accessed, then the B element has become the least recently used elements, moved to the end of the team.

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

1. LRUCache uses the least recently used algorithm, and the least recently used will move to the end of the squad, and the recent use will 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 from the source to learn how to learn LRUCache in the end how to use it:

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


Show a bunch of variables of type int, and one of the most important linkedhashmap<k,v> this queue, the popular linkedhashmap<k,v> is a doubly linked list storage structure.

The meaning of each variable is:

The size already stored in the Size-lrucache

MaxSize-the largest control we define for the LRUCache cache

Number of Putcount-put (the number of times the cache object was added for 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);    }
Find the need to pass in a value of type int, as the name implies, this is the size of the LRUCache cache we have defined, in general we can get the maximum free space of the application, and then set it by the percentage value.

Take a look at some other more 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 you can tell that both key and value cannot be empty, otherwise you will throw 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: The 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, the principle is finished, to see the example of using 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 downloads 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) {//If the cache exists, then the bitmap imageview.setimagebitmap (bitmap) in the cache is set;        } 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 still state, let it download picture 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 image into ImageView * * @param mfirstvisibleitem * @param mvisibleitemcount */Private void LoadBitmap (int mfirstvisibleitem, int mvisibleitemcount) {//First determine if the picture is not in the cache, if not, open the async thread 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) {//start 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; }}

Well, LRUCache introduced to this, the next article disklrucache!!!

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







Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Add the 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.