Android Open Source Framework Universal-image-loader full parsing (iii)---source code interpretation

Source: Internet
Author: User

Reprint Please indicate this article from Xiaanming's blog (http://blog.csdn.net/xiaanming/article/details/39057201 ), please respect the results of other people's hard work, thank you!

This article is mainly to take you from the source of the angle above to read this powerful picture loading frame, oneself a long time did not write the article, feel unfamiliar a lot, distance on an article three months more, really is oneself usually busy, change the work many things to see to understand, and then add oneself also lazy, no before so have passion , I feel this rhythm is not right, I want to continue to maintain the previous passion, is the so-called good memory is inferior to the written, sometimes I will go to look at before writing things, I think the knowledge written down than in the mind retained longer, today to everyone to read the framework of the source, I feel this picture loading framework is really good, After reading the code, I learned a lot. I hope that we can first look at the Android Open source framework Universal-image-loader full parsing (a)---basic introduction and use, Android Open source framework Universal-image-loader full Parse (ii)--- Picture caching strategy in detail, I hope that you can insist on watching, after watching you absolutely have a harvest.

ImageView Mimageview = (ImageView) Findviewbyid (r.id.image);          String IMAGEURL = "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A% 252520photographer.jpg ";                    Displays the configuration of the picture          displayimageoptions options = new Displayimageoptions.builder ()                  . showimageonloading ( r.drawable.ic_stub)                  . Showimageonfail (r.drawable.ic_error).                  Cacheinmemory (True).                  Cacheondisk (True)                  . Bitmapconfig (Bitmap.Config.RGB_565)                  . Build ();                    Imageloader.getinstance (). DisplayImage (ImageUrl, Mimageview, Options);  
Most of the time we are using the above code to load the image, we first look at

public void DisplayImage (String uri, ImageView ImageView, displayimageoptions options) {displayimage (URI, new Imageviewaware (ImageView), options, NULL, NULL);}
From the above code, we can see that it will convert ImageView into Imageviewaware, imageviewaware What is the main thing to do? The class is mainly to ImageView to a wrapper, will imageview strong references into weak references, when the memory is not enough, you can better reclaim ImageView objects, there is to get imageview width and height. This allows us to crop the image according to ImageView's wide height, reducing the use of memory.

Next look at the specific DisplayImage method, because this method code is quite a lot of, so here I separate to read

Checkconfiguration (); if (imageaware = = null) {throw new illegalargumentexception (error_wrong_arguments);} if (listener = = NULL) {listener = Emptylistener;} if (options = = null) {options = configuration.defaultdisplayimageoptions;} if (Textutils.isempty (URI)) {engine.canceldisplaytaskfor (imageaware); listener.onloadingstarted (URI, Imageaware.getwrappedview ()); if (Options.shouldshowimageforemptyuri ()) {imageaware.setimagedrawable ( Options.getimageforemptyuri (Configuration.resources));} else {imageaware.setimagedrawable (null);} Listener.onloadingcomplete (URI, Imageaware.getwrappedview (), null); return;}
The 1th line of code is to check whether Imageloaderconfiguration is initialized, which is done in application

12-21 line is mainly for the time when the URL is empty, the 13th line of code, there is a hashmap in the Imageloaderengine, used to record the task being loaded, Loading the image will add the ImageView ID and the URL of the image to the HashMap, which will be removed after the loading is complete. Then the picture of the Displayimageoptions Imageresforemptyuri is set to ImageView, and the final callback to the Imageloadinglistener interface tells it that the task is complete.

ImageSize targetsize = Imagesizeutils.definetargetsizeforview (Imageaware, Configuration.getmaximagesize ()); String Memorycachekey = Memorycacheutils.generatekey (URI, targetsize); Engine.preparedisplaytaskfor (ImageAware, Memorycachekey); listener.onloadingstarted (URI, Imageaware.getwrappedview ()); Bitmap bmp = Configuration.memoryCache.get (Memorycachekey), if (BMP! = null &&!bmp.isrecycled ()) {L.D (log_load_ Image_from_memory_cache, Memorycachekey), if (Options.shouldpostprocess ()) {Imageloadinginfo ImageLoadingInfo = new Imageloadinginfo (URI, Imageaware, Targetsize, memorycachekey,options, Listener, Progresslistener, Engine.getlockforuri (URI)); Processanddisplayimagetask displaytask = new Processanddisplayimagetask (engine, BMP, Imageloadinginfo,definehandler ( Options)), if (options.issyncloading ()) {Displaytask.run ();} else {engine.submit (displaytask);}} else {Options.getdisplayer (). Display (BMP, Imageaware, Loadedfrom.memory_cache); Listener.onloadingcomplete (URI, Imageaware.getwrappedvieW (), BMP);}} 
The 1th line is mainly to imageview the width of the package into ImageSize objects, if the imageview width of 0, will use the width of the phone screen as the width of the ImageView, we use the Listview,gridview to load the picture, The first page gets the width of 0, so the screen of the phone used on the first page is wide, and the rear gets the size of the control itself.

Line 7th Gets the bitmap object from the memory cache, and we can then configure the memory cache logic in Imageloaderconfiguration, which is used by default Lrumemorycache, which I said in the previous article

There is a judgment in line 11th that we enter the true logic if we set the Postprocessor in Displayimageoptions, but the default postprocessor is null, Bitmapprocessor interface is mainly for the processing of bitmap, this framework does not give a corresponding implementation, if we have their own needs can be implemented Bitmapprocessor interface (such as the picture is set to a circle)

第22-23 line is set bitmap to ImageView above, here we can configure the display requirements Displayer in Displayimageoptions, the default is to use Simplebitmapdisplayer, Directly set bitmap to ImageView above, we can configure other display logic, he provides here fadeinbitmapdisplayer (transparency from 0-1) Roundedbitmapdisplayer (4 corners are arcs), etc. Then callback to the Imageloadinglistener interface

if (options.shouldshowimageonloading ()) {imageaware.setimagedrawable (options.getimageonloading ( configuration.resources));} else if (options.isresetviewbeforeloading ()) {imageaware.setimagedrawable (null);} Imageloadinginfo imageloadinginfo = new Imageloadinginfo (URI, Imageaware, Targetsize, memorycachekey,options, listener , Progresslistener, Engine.getlockforuri (URI)); Loadanddisplayimagetask displaytask = new Loadanddisplayimagetask (engine, Imageloadinginfo,definehandler (options)); if (options.issyncloading ()) {Displaytask.run ();} else {engine.submit (displaytask);}
This code is mainly bitmap not in the memory cache, from the file or the network to get bitmap object, instantiate a Loadanddisplayimagetask object, Loadanddisplayimagetask implemented Runnable, If Issyncloading is configured to True, execute Loadanddisplayimagetask's Run method directly, indicating synchronization, which defaults to false and commits loadanddisplayimagetask to the thread pool object

Next we look at Loadanddisplayimagetask's run (), this class is quite complicated, we are still a section of the analysis

if (waitifpaused ()) return;if (Delayifneed ()) return;

If waitifpaused (), Delayifneed () returns True, returns directly from the run () method without executing the following logic, let's take a look at waitifpaused ()

Private Boolean waitifpaused () {Atomicboolean pause = engine.getpause (); if (Pause.get ()) {synchronized ( Engine.getpauselock ()) {if (Pause.get ()) {L.D (Log_waiting_for_resume, memorycachekey); try {engine.getpauselock (). Wait ();} catch (Interruptedexception e) {L.E (log_task_interrupted, Memorycachekey); return true;} L.D (Log_resume_after_pause, Memorycachekey);}} return istasknotactual ();}

This method is what to use, mainly when we use the Listview,gridview to load the picture, sometimes in order to slide more fluent, we will choose the finger in the slide or a sudden swipe to not load the picture, so we put forward such a method, then how to use it? The Pauseonscrolllistener class is used here, using a very simple Listview.setonscrolllistener (new Pauseonscrolllistener (Pauseonscroll, pauseonfling)), Pauseonscroll control We slowly slide listview,gridview whether to stop loading the picture, pauseonfling control the hard slide Listview,gridview whether to stop loading the picture

In addition, the return value of this method is determined by istasknotactual (), and we then look at the source code of Istasknotactual ().

Private Boolean istasknotactual () {return isviewcollected () | | isviewreused ();}
Isviewcollected () is to determine whether our imageview is recycled by the garbage collector, if it is recycled, the Loadanddisplayimagetask method of Run () is returned directly, isviewreused () Determine if the ImageView is reused, and the Reuse run () method also returns directly, why use the isviewreused () method? Mainly Listview,gridview we will reuse the item object, if we first load Listview,gridview the first page of the picture, the first page of the picture is not all loaded we will quickly scroll, isviewreused () Method will avoid these invisible item to load the picture, and directly load the picture of the current interface
Reentrantlock loadfromurilock = Imageloadinginfo.loadfromurilock; L.D (Log_start_display_image_task, Memorycachekey), if (loadfromurilock.islocked ()) {L.D (Log_waiting_for_image_ LOADED, Memorycachekey);} Loadfromurilock.lock (); Bitmap bmp;try {checktasknotactual (); bmp = Configuration.memoryCache.get (Memorycachekey); if (bmp = = NULL | | Bmp.isrecycled ()) {BMP = Tryloadbitmap (); if (BMP = = null) return;//listener callback already was firedchecktasknotactual (); checktaskinterrupted (); if (Options.shouldpreprocess ()) {L.D (log_preprocess_image, memorycachekey); bmp = Options.getpreprocessor (). Process (BMP), if (BMP = = null) {L.E (error_pre_processor_null, Memorycachekey);}} if (BMP! = null && options.iscacheinmemory ()) {L.D (log_cache_image_in_memory, Memorycachekey); Configuration.memoryCache.put (Memorycachekey, BMP);}} else {loadedfrom = Loadedfrom.memory_cache; L.D (log_get_image_from_memory_cache_after_waiting, Memorycachekey);} if (BMP! = null && options.shouldpostprocess ()) {L.D (log_postProcess_image, memorycachekey), BMP = Options.getpostprocessor (). Process (BMP), if (BMP = = null) {L.E (error_post_ Processor_null, Memorycachekey);}} Checktasknotactual (); checktaskinterrupted ();} catch (Taskcancelledexception e) {firecancelevent (); return;} finally {Loadfromurilock.unlock ();}
The 1th line of code has a loadfromurilock, this is a lock, the method of acquiring the lock is in the Getlockforuri () method of the Imageloaderengine class
Reentrantlock Getlockforuri (String uri) {Reentrantlock lock = Urilocks.get (URI), if (lock = = null) {lock = new Reentrantloc K (); Urilocks.put (URI, lock);} return lock;}
As can be seen from the above, the lock object and the URL of the image is corresponding to each other, why do you want to do this? Also you do not understand, do not know whether we have considered a scene, if in a ListView, an item is in the process of acquiring the picture, and at this time we will roll the item out of the interface and roll it in, after rolling in, if there is no lock, the item will be loaded once the picture, Assuming in a very short period of time scrolling very frequently, then will appear several times to the network to request the picture, so here according to the image URL to a Reentrantlock object, so that the request with the same URL will be in line 7th wait, wait until the picture loading is complete, Reentrantlock is released, and requests for the same URL will continue to execute the code below line 7th

Come to line 12th, they will be taken from the memory cache first, if the memory cache is not going to execute the following logic, so the role of Reentrantlock is to avoid repeated in this case to request a picture from the network.

Line 14th Method Tryloadbitmap (), this method is really a bit long, I first tell you, this is the logic of the first to get from the file cache there are no bitmap objects, if not in the go from the network, and then save bitmap in the file system, we still specifically analyzed

File imagefile = Configuration.diskCache.get (URI); if (imagefile! = null && imagefile.exists ()) {L.D (log_load_ Image_from_disk_cache, memorycachekey); loadedfrom = Loadedfrom.disc_cache;checktasknotactual (); bitmap = DecodeImage (Scheme.FILE.wrap (Imagefile.getabsolutepath ()));}
First judge the file cache there is no such file, if any, go directly to call Decodeimage () method to decode the picture, the method inside call Baseimagedecoder class decode () method, according to the imageview of the width of the high, ScaleType to cut the picture, the specific code I do not introduce, we go to see, we take a look down Tryloadbitmap () method

if (bitmap = = NULL | | bitmap.getwidth () <= 0 | | bitmap.getheight () <= 0) {L.D (log_load_image_from_network, MEMORYCAC Hekey); loadedfrom = Loadedfrom.network; String imageurifordecoding = uri;if (Options.iscacheondisk () && Trycacheimageondisk ()) {ImageFile = Configuration.diskCache.get (URI); if (imagefile! = null) {imageurifordecoding = Scheme.FILE.wrap ( Imagefile.getabsolutepath ());}} Checktasknotactual (); bitmap = Decodeimage (imageurifordecoding); if (bitmap = = NULL | | bitmap.getwidth () <= 0 | | bitmap. GetHeight () <= 0) {firefailevent (failtype.decoding_error, NULL);}}
Line 1th indicates that the bitmap obtained from the file cache is null, or the width is 0, go to the network to get bitmap, to the 6th line of code is configured Displayimageoptions Iscacheondisk, Indicates whether the bitmap object needs to be saved in the file system, generally we need to configure to true, the default is false this to note, and then is to execute the Trycacheimageondisk () method, go to the server to pull the picture and save in the local file

Private Bitmap Decodeimage (String Imageuri) throws IOException {Viewscaletype Viewscaletype = Imageaware.getscaletype () ; Imagedecodinginfo decodinginfo = new Imagedecodinginfo (Memorycachekey, Imageuri, Uri, Targetsize, ViewScaleType, Getdownloader (), options); return Decoder.decode (Decodinginfo);} /** @return <b>true</b>-If image was downloaded successfully; <b>false</b>-otherwise */private boolean trycacheimageondisk () throws Taskcancelledexception {L.D (log_ Cache_image_on_disk, Memorycachekey); Boolean loaded;try {loaded = Downloadimage (); if (loaded) {int width = Configuration . maximagewidthfordiskcache;int height = configuration.maximageheightfordiskcache;if (Width > 0 | | height > 0) {L.D ( Log_resize_cached_image_file, Memorycachekey); resizeandsaveimage (width, height); Todo:process boolean Result}}} catch (IOException e) {L.E (e); loaded = false;} return loaded;} Private Boolean Downloadimage () throws IOException {InputStream is = Getdownloader (). GetStream(URI, Options.getextrafordownloader ()); return Configuration.diskCache.save (URI, is, this);} 
The Downloadimage () method in line 6th is responsible for downloading the picture and keeping it in the file cache, and will download the progress of the saved bitmap callback to the onbytescopied of the Ioutils.copylistener interface (int current, int Total) method, so we can set the Imageloadingprogresslistener interface to get the picture download save progress, here the picture saved in the file system is the original image

第16-17 row, gets whether imageloaderconfiguration sets the size of the picture saved in the file system, if Maximagewidthfordiskcache and Maximageheightfordiskcache are set, Will call the Resizeandsaveimage () method to crop the picture and then replace the original image, save the cropped picture to the file system, before a classmate asked me that the framework is saved in the file system of the picture is the original image, how to save the thumbnail image, Just set Maximagewidthfordiskcache and Maximageheightfordiskcache when you instantiate imageloaderconfiguration in application.

if (BMP = = null) return; Listener callback already was firedchecktasknotactual (); checktaskinterrupted (); if (Options.shouldpreprocess ()) { L.D (Log_preprocess_image, memorycachekey), BMP = Options.getpreprocessor (). Process (BMP), if (BMP = = null) {L.E (error_ Pre_processor_null, Memorycachekey);}} if (BMP! = null && options.iscacheinmemory ()) {L.D (log_cache_image_in_memory, Memorycachekey); Configuration.memoryCache.put (Memorycachekey, BMP);}
Next here is simple, 6-12 row whether to deal with bitmap, this need to implement, 14-17 is to save the picture in the memory cache

Displaybitmaptask displaybitmaptask = new Displaybitmaptask (BMP, Imageloadinginfo, engine, Loadedfrom); RunTask ( Displaybitmaptask, syncloading, Handler, engine);
The last two lines of code are a display task that looks directly at the Displaybitmaptask class's Run () method

@Overridepublic void Run () {if (imageaware.iscollected ()) {L.D (log_task_cancelled_imageaware_collected, Memorycachekey); listener.onloadingcancelled (Imageuri, Imageaware.getwrappedview ());} else if (isviewwasreused ()) {L.D (log_task_cancelled_imageaware_reused, memorycachekey); listener.onloadingcancelled (Imageuri, Imageaware.getwrappedview ());} else {L.D (Log_display_image_in_imageaware, Loadedfrom, Memorycachekey);d isplayer.display (bitmap, Imageaware, Loadedfrom); engine.canceldisplaytaskfor (Imageaware); Listener.onloadingcomplete (Imageuri, Imageaware.getwrappedview (), bitmap);}}

If ImageView is recycled or reused, callback to Imageloadinglistener interface, otherwise call Bitmapdisplayer to show bitmap

Article written here has been written, do not know that there is no further understanding of the open source framework, the open source framework design is also very flexible, with a lot of design patterns, such as builder mode, decoration mode, proxy mode, strategy mode, etc., so as to facilitate our expansion, to achieve the function we want, Today's explanation is here, there is no understanding of the framework of the place can leave a message below, I will try to answer for everyone.






Android Open Source Framework Universal-image-loader full parsing (iii)---source code interpretation

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.