# # Prefaceteaching you to write the basic architecture of Android Imageloader framework we have a basic introduction to the Simpleimageloader framework, today we will be from the perspective of the source code to analyze the design and implementation of Imageloader.
Before we use Imageloader, we will set up some basic things through a configuration class, such as loading pictures, loading failed images, caching policies and so on, Simpleimageloader design is the same. Configuration class This is relatively simple, we directly look at the source bar.
Imageloaderconfig Configuration
/** * Imageloader Configuration class, * * @author mrsimple */public class Imageloaderconfig {/** * Picture cache Config Object */public BITM Apcache Bitmapcache = new MemoryCache (); /** * Loading and load failed picture configuration object when loading picture */public displayconfig displayconfig = new Displayconfig (); /** * Load Policy */public Loadpolicy loadpolicy = new Serialpolicy (); /** * * */public int threadcount = Runtime.getruntime (). Availableprocessors () + 1; /** * @param count * @return */public imageloaderconfig setthreadcount (int count) {threadcount = M Ath.max (1, threadcount); return this; } public Imageloaderconfig Setcache (Bitmapcache cache) {Bitmapcache = cache; return this; } public imageloaderconfig setloadingplaceholder (int resId) {displayconfig.loadingresid = ResId; return this; } public imageloaderconfig setnotfoundplaceholder (int resId) {displayconfig.failedresid = ResId; return this; } PubLic Imageloaderconfig Setloadpolicy (Loadpolicy policy) {if (policy! = null) {Loadpolicy = policy; } return this; }}
are simple setter functions, but the difference is that these setters return a Imageloaderconfig object, and in this case it returns itself. This design is similar to the builder pattern, which facilitates user-linked invocation, such as:
```
private void Initimageloader () {
Imageloaderconfig config = new Imageloaderconfig ()
. Setloadingplaceholder (r.drawable.loading)
. Setnotfoundplaceholder (R.drawable.not_found)
. Setcache (New Doublecache (This))
. Setthreadcount (4)
. Setloadpolicy (New Reversepolicy ());
Initialization
Simpleimageloader.getinstance (). init (config);
}
```
for those of you who are not familiar with the builder model, you can refer to the builder mode of Android source analysis. After the configuration object is built, we can initialize the Simpleimageloader with this configuration object. Simpleimageloader initializes some internal policies based on the configuration object, such as the cache policy, the number of threads, and so on. After calling the Init method, the entire imageloader is officially started.
The realization of SimpleimageloaderSimpleimageloader This class of responsibility is only as a user portal, it's not so much work, just a doorman. Let's take a look at its source code.
/** * Image loading class, support URL and local image URI form load. According to the image Path format to determine whether it is a network picture or local picture, if the network picture is given to the simplenet framework to load, * If it's a local picture, then give it to Mexecutorservice from the SD card *. The UI is updated directly after loading without user intervention. If the user sets a cache policy, the loaded picture is cached. Users can also set load policies, such as sequential loading {@see * Serialpolicy} and reverse load {@see Reversepolicy}. * * @author mrsimple */public final class Simpleimageloader {/** simpleimageloader instance */private static SimpleImage Loader sinstance; /** Network Request queue */private requestqueue mimagequeue; /** Cache */private volatile bitmapcache Mcache = new MemoryCache (); /** Picture Load Config Object */private Imageloaderconfig mconfig; Private Simpleimageloader () {}/** * get imageloader single Case * * @return */public static Simpleimagelo Ader getinstance () {if (sinstance = = null) {synchronized (Simpleimageloader.class) {if (sinstance = = null) {sinstance = new Simpleimageloader (); }}} return sinstance; }/** * Initialize Imageloader, start request queue * @paramConfig Config object */public void init (imageloaderconfig config) {mconfig = config; Mcache = Mconfig.bitmapcache; Checkconfig (); Mimagequeue = new Requestqueue (mconfig.threadcount); Mimagequeue.start (); private void Checkconfig () {if (mconfig = = null) {throw new RuntimeException ( The config of Simpleimageloader is Null, click the init (imageloaderconfig config) method to initialize "); } if (mconfig.loadpolicy = = null) {Mconfig.loadpolicy = new serialpolicy (); } if (Mcache = = null) {Mcache = new NoCache (); }} public void DisplayImage (ImageView ImageView, String uri) {displayimage (ImageView, URI, NULL, NULL); public void DisplayImage (final ImageView ImageView, final String Uri, Final displayconfig config, final I Magelistener listener) {bitmaprequest request = new Bitmaprequest (ImageView, Uri, config,Listener); The configuration object that is loaded, if not set, is configured with Imageloader Request.displayconfig = request.displayconfig! = null? Request.displayConfig:mConfig.displayConfig; Add the Mimagequeue.addrequest to the queue (request); }//code omitted .../** * Picture loading listener * * @author mrsimple */public static interface Imagelistener { public void OnComplete (ImageView ImageView, Bitmap Bitmap, String URI); }}
from the above code we can see that Simpleimageloader's work is relatively small, but also relatively simple. It initializes the Imageloader based on the configuration that the user has passed in, and as a picture-loading portal, the user calls DisplayImage and then encapsulates the call as a bitmaprequest request and adds the request to the request queue.
Bitmaprequest Picture Load RequestBitmaprequest is just an object that stores the ImageView, image Uri, Displayconfig, and Imagelistener, and encapsulates the object's purpose to reduce the number of arguments when loading the image, * * * In the Bitmaprequest constructor we will set the image URI to the ImageView tag, which is done to prevent the image from being misaligned. The Bitmaprequest class implements the Compare interface, and the request queue is sorted according to its sequence number, and the ordering policy user can also be set by the configuration class, and the specifics are discussed in the section on loading the policy.
Public Bitmaprequest (ImageView ImageView, String Uri, displayconfig config, Imagelistener listener) { Mimageviewref = new weakreference<imageview> (ImageView); displayconfig = config; Imagelistener = listener; Imageuri = URI; Set the ImageView tag for the picture Uri Imageview.settag (URI); ImageUriMd5 = MD5HELPER.TOMD5 (Imageuri); }
Requestqueue Picture Request queueRequest queue We used the same pattern in simplenet, by encapsulating a priority queue to maintain the picture loading queue, Mserialnumgenerator assigns a serial number to each request, Priorityblockingqueue will determine the order of bitmaprequest based on the compare strategy of bitmaprequest. The Requestqueue internally initiates a user-specified number of threads to read requests from the request queue, and the distribution thread continuously reads the request from the queue and then handles the picture loading so that imageloader happy up.
/** * Request queue, use priority queue, so that requests can be processed by priority. [Thread Safe] * * @author mrsimple */public final class Requestqueue {/** * request queue [Thread-safe] */priv Ate blockingqueue<bitmaprequest> mrequestqueue = new priorityblockingqueue<bitmaprequest> (); /** * Requested serialization generator */private Atomicinteger mserialnumgenerator = new Atomicinteger (0); /** * Default number of cores */public static int default_core_nums = Runtime.getruntime (). Availableprocessors () + 1; /** * Number of CPU cores + 1 distribution threads */private int mdispatchernums = Default_core_nums; /** * Networkexecutor, the thread executing the network request */private requestdispatcher[] mdispatchers = null; /** * */protected Requestqueue () {this (default_core_nums); }/** * @param corenums thread Core number * @param httpstack HTTP Executor */protected requestqueue (int corenums) { Mdispatchernums = Corenums; }/** * Start RequestDispatcher */private final void Startdispatchers () {MDIspatchers = new Requestdispatcher[mdispatchernums]; for (int i = 0; i < mdispatchernums; i++) {mdispatchers[i] = new RequestDispatcher (mrequestqueue); Mdispatchers[i].start (); }} public void Start () {Stop (); Startdispatchers (); }/** * Stop RequestDispatcher */public void Stop () {if (mdispatchers! = null && mdispatchers. Length > 0) {for (int i = 0; i < mdispatchers.length; i++) {mdispatchers[i].interrupt (); }}}/** * cannot repeat add request * @param request */public void addrequest (Bitmaprequest requ EST) {if (!mrequestqueue.contains (Request)) {Request.serialnum = This.generateserialnumber (); Mrequestqueue.add (Request); } else {log.d ("", "# # # Request queue already contains"); }} private int generateserialnumber () {return mserialnumgenerator.incrementandget (); }} "# # REQUESTDISPATCHer request distribution request dispatcher, inherits from the thread, from the network request queue to iterate the request and executes, also relatively simple, directly on the source bar. ' Final class RequestDispatcher extends Thread {/** * Network request queue */Private blockingqueue<bitmaprequest> Mrequestqueue; /** * @param queue picture Load request queues */public RequestDispatcher (blockingqueue<bitmaprequest> queue) {Mreq Uestqueue = queue; } @Override public void Run () {try {while (!this.isinterrupted ()) {final BITMAPR Equest request = Mrequestqueue.take (); if (Request.iscancel) {continue; }//Parse Picture schema final String schema = Parseschema (Request.imageuri); The corresponding Loader Loader imageloader = Loadermanager.getinstance () is obtained according to the schema. Getloader (schema); Load Picture imageloader.loadimage (request); }} catch (Interruptedexception e) {log.i ("", "# # # Request Dispatcher exit"); }}/** * Here is the format for parsing the image URI, in the following URI format: schema://+ picture path. */private string Parseschema (string uri) {if (Uri.contains ("://")) {return Uri.split ("://") [0]; } else {LOG.E (GetName (), "# # wrong scheme, image URI is:" + URI); } return ""; }}
The first point is the run function, constantly get the request from the queue, and then resolve to the picture URI schema, from the format of the schema to know where it is stored in the picture. For example, the schema of the Network Picture object is HTTP or the HTTPS,SD card stores the image corresponding to the schema of file. Based on the schema we get the corresponding loader from the Loadermanager to load the image, this design guarantees the extensibility of the Simpleimageloader loadable image type, which is why it is added loader this package. The user simply constructs the picture URI according to the URI format, implements its own loader class, and then injects the loader object into the Loadermanager, which we will elaborate later.
Another focus here is the Parseschema function, which is responsible for parsing the image Uri format, the URI format is: schema://+ picture path, for example, the network picture format is http://xxx.image.jpg, and the local picture URI is file:/// Sdcard/xxx/image.jpg. If you want to implement your own loader to load a particular format, then its URI format must start with schema://, otherwise the parsing will be wrong, for example, can be drawable://image, and then you register a schema as "drawable" Loader to Loadermanager, Simpleimageloader loads pictures using your registered loader to load images, so you can respond to the diverse needs of your users. If you can't embrace change, you can't call it a frame, it should be called a function module.
This chapter summarizesFinally, let's tidy up the process, Simpleimageloader configure and start the request queue based on the user's configuration, and the request queue launches several distribution threads based on the number of threads configured by the user. These threads continuously read the picture load request from the request queue (thread safe) and perform a picture load request. These requests are generated by the user calling Simpleimageloader's DisplayImage function, which encapsulates the call as a Bitmaprequest object and adds the object to the request queue. This gives the producer (the user) and the consumer (the distribution thread), the whole Simpleimageloader with the CPU beating and boiling up!
GitHub Warehouse Links
Simpleimageloader Warehouse Address
If you think I'm good at writing, then help me top it! thanks~
Teach you to write the initial configuration and request scheduling of Android Imageloader framework