In teaching you to write the initial configuration and request scheduling of the Android Imageloader framework, we have described the design and implementation of Imageloader's request configuration and scheduling. Today we are going to learn more about the specific loading process of the picture and the loaded strategy (including sequential loading and reverse loading), where I will share some of my design decisions and welcome suggestions.
The implementation of loading loader and loadermanager of picture
In the previous article that taught you to write the initial configuration and request scheduling of the Android Imageloader framework, we talked about loader and Loadermanager. Imageloader constantly gets the request from the queue and resolves it to the schema of the picture Uri, which can be used to know where the image is stored, from the schema format. For example, the schema of the network Picture object is an HTTP or https,sd card stored image corresponding to the schema for the File,schemae and loader have a correspondence relationship. According to the schema we get the corresponding loader from the Loadermanager to load the picture. This design guarantees the scalability of the Simpleimageloader loadable image type, which is why the loader is added to this package. The user simply constructs the picture URI based on the format of the URI, implements its own loader class, and injects the loader object into the Loadermanager. The run function in RequestDispatcher is as follows:
@Override Public void Run() {Try{ while(! This. isinterrupted ()) {FinalBitmaprequest request = Mrequestqueue.take ();if(Request.iscancel) {Continue; }FinalString schema = Parseschema (Request.imageuri);//Get loader based on schemaLoader Imageloader = Loadermanager.getinstance (). Getloader (schema); Imageloader.loadimage (Request); } }Catch(Interruptedexception e) {LOG.I ("","# # # Request Dispatcher exits"); } }
Loader only defines an interface, using only one method of loading the image.
publicinterface Loader { publicvoidloadImage(BitmapRequest result);}
Abstract is to be extensible, define this interface, we can inject our own picture load implementation class. For example, loading from resources, assets. Regardless of whether you load the picture from the network or locally, we have several steps to load the picture:
- Determines whether the image is contained in the cache;
- If any, post the picture directly to the UI thread and update the UI;
- If there is no cache, get the picture from the corresponding place, and cache the picture, then post the result to the UI thread and update the UI;
We can see that the logic is universal, no matter where the images are loaded, so I abstracted a absloader class. It abstracts these processes and only gives the changed parts to the subclass, which is equivalent to Absloader encapsulating a logical framework (which can be thought about what design patterns are used), roughly the following code:
/** * @author mrsimple * * Public Abstract class absloader implements Loader { /** * Picture Cache * / Private StaticBitmapcache Mcache = Simpleimageloader.getinstance (). GetConfig (). Bitmapcache;@Override Public Final void LoadImage(Bitmaprequest request) {//1, get from cacheBitmap Resultbitmap = mcache.get (request); LOG.E ("","# # # whether there is a cache:"+ Resultbitmap +", Uri ="+ Request.imageuri);if(Resultbitmap = =NULL) {showloading (request);///2, no cache, call onloaderimage load pictureResultbitmap = onloadimage (request);//3, cache pictureCachebitmap (Request, RESULTBITMAP); }Else{Request.justcacheinmem =true; }//Post the results to the UI threadDeliverytouithread (Request, RESULTBITMAP); }/** Loading the image of the hook method, left to subclass processing * @param request * @return * * protected AbstractBitmapOnloadimage(Bitmaprequest request);//Code omission}
The code logic implements a template function as described above, and the changing part is onloadimage, where subclasses implement the actual method of loading the image. For example, loading images from a network.
/** * @author mrsimple * * Public class UrlLoader extends absloader { @Override PublicBitmapOnloadimage(Bitmaprequest request) {FinalString imageUrl = Request.imageuri; FileOutputStream fos =NULL; InputStream is =NULL;Try{URL url =NewURL (IMAGEURL);FinalHttpURLConnection conn = (httpurlconnection) url.openconnection (); is =NewBufferedinputstream (Conn.getinputstream ()); Is.mark (Is.available ());FinalInputStream InputStream = is; Bitmapdecoder Bitmapdecoder =NewBitmapdecoder () {@Override PublicBitmapdecodebitmapwithoption(Options Options) {Bitmap Bitmap = Bitmapfactory.decodestream (InputStream,NULL, options);// if(options.injustdecodebounds) {Try{Inputstream.reset (); }Catch(IOException e) {E.printstacktrace (); } }Else{//Close streamConn.disconnect (); }returnBitmap } };returnBitmapdecoder.decodebitmap (Request.getimageviewwidth (), Request.getimageviewheight ()); }Catch(Exception e) { }finally{ioutil.closequietly (IS); ioutil.closequietly (FOS); }return NULL; }}
When initializing Imageloader, we will inject several loader into the Loadermanager by default, then when loading the picture imageloader will get corresponding loader according to the picture schema to complete the loading function.
/** * */ privateLoaderManager() { new UrlLoader()); new UrlLoader()); new LocalLoader()); }
Load Policy
The load policy is your picture loading request after the submission of imageloader follow a rule to load your request. The default is the Serialpolicy policy (FIFO), who is in front of the queue who is first executed. But things are often not as simple as when we scroll in the ListView, we want the last pictures added to the request queue to take precedence, so they're on the phone screen at this point, so we've added a reversepolicy strategy. Well, for this existence of various possibilities of the part, we can not materialize, or to abstract! So I defined the Loadpolicy interface, which functions as a compare of two requests to define the sorting principle.
publicinterface LoadPolicy { publicintcompare(BitmapRequest request1, BitmapRequest request2);}
Because our request queue uses the priority queue Priorityblockingqueue, our bitmaprequest implements the comparable interface. We delegate CompareTo to the compare of the Loadpolicy object in the Bitmaprequest function.
@Override publicintcompareTo(BitmapRequest another) { return mLoadPolicy.compare(this, another); }
Let's look at the default load policy, which is loaded sequentially, and the requests added to the queue are executed first.
/** * 顺序加载策略 * * @author mrsimple */publicclass SerialPolicy implements LoadPolicy { @Override publicintcompare(BitmapRequest request1, BitmapRequest request2) { // 那么按照添加到队列的序列号顺序来执行 return request1.serialNum - request2.serialNum; }}
The reverse load is:
/** * Reverse load policy, which is loaded from the last request to join the queue * * @author mrsimple */ public class reversepolicy implements loadpolicy { @Override public int compare (Bitmaprequest request1, Bitmaprequest request2) {//note bitmap request to perform the latest queue-join request, Imageloader's policy ret Urn request2.serialnum-request1.serialnum; }}
Oh, think this is not a strategy mode! The original pattern is everywhere, and when you get used to it you will find that the pattern has been applied to your code in the invisible. As shown above, the strategy is a simple implementation, the policy only needs to be specified when configuring Imageloader, the user can also implement the policy class according to their own needs, and injected to Imageloader. This guarantees flexibility and scalability.
Summarize
Loader and Loadermanager guarantee the scalability of the loadable image source, that is, the picture can be stored on the network, SD card, res folder and so on, to implement a loader from a specific location to load the picture, and then to this loader register a schema, When loading the picture, we get the schema according to the path of the picture, then get loader through the schema and load the picture through loader.
and the loading strategy of the picture is loadpolicy by this abstraction, the user can implement the loading strategy by itself. This guarantees flexibility and, of course, a later image cache that also requires the same flexibility. And I say in the object-oriented six principles of the public technology point, the object-oriented principles are finally translated into a few simple keywords: abstract, single duty, minimized. Understanding these ideas, I think your code quality should have a qualitative improvement.
Imageloader Library, image caching is definitely essential. About the image of the cache design, or the old saying, I will explain next
Teach you to write pictures of Android Imageloader frame loading and loading strategy