Android introduces cache full resolution for asynchronous loading
Why to CacheWith image scaling, we're doing a big picture of the optimizations for asynchronous loading, but now the app is not just a big picture of HD. Figure. It is a picture-and-text mix. In the image, assume that the images are loaded into memory. Must be oom. Therefore, after the user has browsed through the image. These discarded images should be recycled right away, but. This brings another problem. That is, when the user after browsing through a picture, assuming that you want to go back again to browse again, then these recycled images will be loaded again, not guaranteed to those who are bored to the pain of the egg on the side to see you recycle GC. While watching you load again. These two things are bound to contradict each other. is also a very important factor that affects performance.
Memory CacheGoogle offers a set of memory caching techniques for a problem that really needs to find a balance point.
Memory caching technology provides a high-speed way to access images that consume valuable memory from applications. The core of the class is LRUCache. This class is ideal for caching images, and its main algorithm is to store recently used objects in linkedhashmap with strong references, and to remove the least recently used objects from memory before the cache value reaches a predetermined value. LruCache was introduced in SUPPORT-V4 before the introduction of LruCache. Google recommends using soft or weak references (softreference or weakreference) for memory caching. However, from the beginning of Android 2.3, the GC algorithm changes, soft references and weak references will be the same priority by GC recycling. So this method also does not have too high use value, today on the Internet very much still continue to using SoftReference and WeakReference article. Most of them are outdated articles, suggest that we keep up with the pace of the party, with the Times.
The memory cache size used by LRUCache using the memory cache LRUCache is determined by the developer. Developers need to take into account the image usage, resolution, frequency of access, device performance and many other factors.
This balance often requires a lot of experience and testing to decide.
Using LRUCache is very easy:
Private lrucache<string, bitmap> mmemorycaches;//gets the application memory int maxmemory = (int) runtime.getruntime (). MaxMemory (); /Assign Cacheint cacheSize = maxmemory/10;mmemorycaches = new lrucache<string, bitmap> (cacheSize) { @Override
protected int sizeOf (String key, Bitmap value) { return value.getbytecount (); } };/ /from LRUCache Gets the cache object public Bitmap getbitmapfrommemorycaches (String url) { return mmemorycaches.get (URL);} Add a cache object to Lrucachepublic void Addbitmaptomemorycaches (String url,bitmap Bitmap) { if (getbitmapfrommemorycaches ( URL) = = null) { mmemorycaches.put (URL, bitmap);} }
First, we need to declare lrucache. Then. Create a cache object with LRUCache's construction method and assign it cachesize, this cachesize usually we need to get through runtime to get the available memory that the current system distributes to the app, and use a portion of that memory as a LRUCache cache. The sizeof method must be overridden in LRUCache. In this way, LRUCache can get the size of each cache object. Subclasses must be overridden. Because the default LRUCache gets the number of caches.
。。 Nima. Finally, we provide two methods getbitmapfrommemorycaches and addbitmaptomemorycaches to get and add the memory cache to LRUCache, respectively. Wait, we seem to have not written the method of releasing memory, yes, you do not have to write, the LRU algorithm can ensure that CacheSize will not oom, once the size of this, the GC will reclaim the longest object, free space.
Add a level cache OK for asynchronous processing. After understanding the basic information about the cache, let's go back to this example and figure out how to use caching to optimize for asynchronous processing. First, the ListView, the GridView, these spoiled gadgets. Touch not to fall, not to be happy when it rolled, you still in the back to play hard to load. So, the first point, roll the time to let it happy to roll, and then start loading.
Roll over and reload to achieve this, we can do this by adding the Abslistview.onscrolllistener interface to adapter. Of course, another point to note, the first time initialization, it is necessary to manually load the picture, otherwise the system infers that you did not roll, only can call the Onscroll method, will not call the Onscrollstatechanged method. And we need to constantly get the visible item in the Onscroll method. Special note is VisibleItemCount, only to more than 0 times, only to feel that it is beginning to show the picture.
@Overridepublic void onscrollstatechanged (abslistview view, int scrollstate) { if (scrollstate = = Scroll_state_idle ) { mimageloader.loadimages (Mstart, mEnd); } else { mimageloader.cancelalltasks (); }} @Overridepublic void Onscroll (abslistview view, int firstvisibleitem, int visibleitemcount, int totalitemcount) { Mstart = Firstvisibleitem; MEnd = Firstvisibleitem + visibleitemcount; if (mfirstflag && visibleitemcount > 0) { mimageloader.loadimages (Mstart, mEnd); Mfirstflag = false; }}
Loading the displayed itemsWhen loading data, get the first item that can be displayed and the last visible item, just load this part. So we create a method--loadimages (int start, int end). This method is used to load the item data from start to end.When loading, first from the memory cache to fetch, fake, that indicates the recent has been loaded, that directly loaded on the good, assuming not taken, then open synctask to download.
public void loadimages (int start, int end) {for (int i = start; i < end; i++) { String url = images.image_urls [i]; Bitmap Bitmap = getbitmapfrommemorycaches (URL); if (bitmap = = null) { asyncdownloadimage task = new asyncdownloadimage (URL); Mtasks.add (Task); Task.execute (URL); } else { ImageView ImageView = (ImageView) mlistview.findviewwithtag (URL); Imageview.setimagebitmap (bitmap);}}}
Here we set the picture, directly through the Findviewwithtag. The URL to find the corresponding ImageView, this is different from the previous because we are here according to start to end to load, directly from the ListView object to obtain the corresponding ImageView is relatively simple.
Download and AsynctaskDownloading is still using the old method:
private static Bitmap Getbitmapfromurl (String urlstring) { Bitmap Bitmap; InputStream is = null; try { url url = new URL (urlstring); HttpURLConnection conn = (httpurlconnection) url.openconnection (); is = new Bufferedinputstream (Conn.getinputstream ()); Bitmap = Bitmapfactory.decodestream (is); Conn.disconnect (); return bitmap; } catch (Exception e) { e.printstacktrace (); } finally { try { if (is! = null) is.close (); } catch (IOException e) { } } return null;}
Asynctask is basically similar to the previous:
Class Asyncdownloadimage extends Asynctask<string, Void, bitmap> { private String URL; Public asyncdownloadimage (String URL) { this.url = URL; } @Override protected Bitmap doinbackground (String ... params) { URL = params[0]; Bitmap Bitmap = getbitmapfromurl (URL); if (bitmap! = null) { addbitmaptomemorycaches (URL, bitmap); } return bitmap; } @Override protected void OnPostExecute (Bitmap Bitmap) { super.onpostexecute (Bitmap); ImageView ImageView = (ImageView) mlistview.findviewwithtag (URL); if (ImageView! = null && bitmap! = null) { imageview.setimagebitmap (bitmap); } Mtasks.remove (this);} }
The only difference is. After we download the image. The image is loaded into the LRUCache.
AssemblyOK, everything has. Prepare to brush the code. Before the brush, we first come up with another idea, first of all, in the adapter, one load into the ListView, start to download the display range of item's image, when the cache is of course not. So it's all downloaded, and it's done in item and cached. Assuming it's not finished, you can't wait to get out of the way, so cancel all the tasks immediately. Let the ListView roll merrily. After you have finished rolling, continue loading.OK, that's all for the talk, the following we started to brush the code. All in all, there is only code that knows you best.
Package Com.imooc.listviewacyncloader;import Android.graphics.bitmap;import Android.graphics.bitmapfactory;import Android.os.asynctask;import Android.util.lrucache;import Android.widget.imageview;import Android.widget.ListView; Import Java.io.bufferedinputstream;import Java.io.ioexception;import Java.io.inputstream;import Java.net.httpurlconnection;import Java.net.url;import Java.util.hashset;import Java.util.Set;public class imageloaderwithcaches {private set<asyncdownloadimage> mtasks; Private lrucache<string, bitmap> mmemorycaches; Private ListView Mlistview; Public Imageloaderwithcaches (ListView listview) {This.mlistview = ListView; Mtasks = new hashset<> (); int maxmemory = (int) runtime.getruntime (). MaxMemory (); int cacheSize = MAXMEMORY/10; Mmemorycaches = new lrucache<string, bitmap> (cacheSize) {@Override protected int sizeOf (Strin G key, Bitmap value) {return value.geTbytecount (); } }; } public void ShowImage (String url, ImageView ImageView) {Bitmap Bitmap = getbitmapfrommemorycaches (URL); if (bitmap = = null) {Imageview.setimageresource (r.drawable.ic_launcher); } else {imageview.setimagebitmap (bitmap); }} public Bitmap getbitmapfrommemorycaches (String URL) {return mmemorycaches.get (URL); public void Addbitmaptomemorycaches (String url,bitmap Bitmap) {if (getbitmapfrommemorycaches (URL) = = null) { Mmemorycaches.put (URL, bitmap); }} public void Loadimages (int start, int end) {for (int i = start; i < end; i++) {String URL = Images.image_urls[i]; Bitmap Bitmap = getbitmapfrommemorycaches (URL); if (bitmap = = null) {asyncdownloadimage task = new asyncdownloadimage (URL); Mtasks.add (Task); Task.execute (URL); } else { ImageView ImageView = (ImageView) mlistview.findviewwithtag (URL); Imageview.setimagebitmap (bitmap); }}} private static Bitmap Getbitmapfromurl (String urlstring) {Bitmap Bitmap; InputStream is = null; try {URL url = new URL (urlstring); HttpURLConnection conn = (httpurlconnection) url.openconnection (); is = new Bufferedinputstream (Conn.getinputstream ()); Bitmap = Bitmapfactory.decodestream (IS); Conn.disconnect (); return bitmap; } catch (Exception e) {e.printstacktrace (); } finally {try {if (is! = null) is.close (); } catch (IOException e) {}} return null; public void Cancelalltasks () {if (mtasks! = null) {for (Asyncdownloadimage task:mtasks) { Task.cancel (FALSE); }}} class AsynCdownloadimage extends Asynctask<string, Void, bitmap> {private String URL; Public asyncdownloadimage (String url) {this.url = URL; } @Override protected Bitmap doinbackground (String ... params) {URL = params[0]; Bitmap Bitmap = getbitmapfromurl (URL); if (bitmap! = null) {addbitmaptomemorycaches (URL, bitmap); } return bitmap; } @Override protected void OnPostExecute (Bitmap Bitmap) {super.onpostexecute (BITMAP); ImageView ImageView = (ImageView) mlistview.findviewwithtag (URL); if (ImageView! = null && bitmap! = null) {Imageview.setimagebitmap (bitmap); } mtasks.remove (this); } }}
The following is the code for adapter:
Package Com.imooc.listviewacyncloader;import Android.content.context;import Android.view.layoutinflater;import Android.view.view;import Android.view.viewgroup;import Android.widget.abslistview;import Android.widget.baseadapter;import Android.widget.imageview;import Android.widget.listview;import java.util.List; public class Myadapterusecaches extends Baseadapter implements Abslistview.onscrolllistener {private LAYOUTINFL Ater Minflater; Private list<string> Mdata; Private Imageloaderwithcaches Mimageloader; private int mstart = 0, mEnd = 0; Private Boolean Mfirstflag; Public Myadapterusecaches (context context, list<string> data, ListView listview) {this.mdata = data; Minflater = Layoutinflater.from (context); Mimageloader = new Imageloaderwithcaches (ListView); Mimageloader.loadimages (Mstart, mEnd); Mfirstflag = true; Listview.setonscrolllistener (this); } @Override public int getcount () {return Mdata.size (); } @Override public Object getItem (int position) {return mdata.get (position); } @Override public long getitemid (int position) {return position; } @Override public View getView (int position, view Convertview, ViewGroup parent) {String URL = mdata.get (PO Sition); Viewholder viewholder = null; if (Convertview = = null) {Viewholder = new Viewholder (); Convertview = minflater.inflate (R.layout.listview_item, NULL); Viewholder.imageview = (ImageView) Convertview.findviewbyid (R.id.iv_lv_item); Convertview.settag (Viewholder); } else {Viewholder = (Viewholder) convertview.gettag (); } viewHolder.imageView.setTag (URL); ViewHolder.imageView.setImageResource (R.drawable.ic_launcher); Mimageloader.showimage (URL, viewholder.imageview); return convertview; } @Override public void onscrollstatechanged (ABslistview view, int scrollstate) {if (scrollstate = = Scroll_state_idle) {mimageloader.loadimages (Msta RT, MEnd); } else {mimageloader.cancelalltasks (); }} @Override public void onscroll (Abslistview view, int firstvisibleitem, int visibleitemcount, int totalitemcou NT) {mstart = Firstvisibleitem; MEnd = Firstvisibleitem + visibleitemcount; if (mfirstflag && visibleitemcount > 0) {mimageloader.loadimages (Mstart, mEnd); Mfirstflag = false; }} public class Viewholder {public ImageView ImageView; }}
is not very easy, now introduced cache, downloaded images will be temporarily saved in memory. Mom doesn't have to worry about your oom anymore.Let's try it out, the downloaded picture reappears and can be loaded immediately, unless too many slides lead to the GC.
can just see. Here are a few features of our use of caching for loading:1. When initializing, load2. When sliding, only load3. Loaded content Staging cache4. Loading only the displayed area
We will continue to optimize the cache later. To be continued ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ my github
My video Acres class network
Copyright notice: This article Bo Master original article. Blog, not reproduced without consent.
Android introduces cache full resolution for asynchronous loading