Android-Universal-Image-Loader (asynchronous Image loading cache Library) source code

Source: Internet
Author: User

Android-Universal-Image-Loader (asynchronous Image loading cache Library) source code
In Android development, image loading can be said to be a common problem. image loading is a pitfall, and there may be various strange problems due to poor processing, for example, loading causes interface freezing and program crash.
Therefore, how to efficiently load a large number of images and how to load images with high resolution to the memory is a problem that we have to face and solve when developing a high-quality app.
In normal development, we only have two options: ① using open-source frameworks ② processing image loading and caching by ourselves.
We usually have to write it by ourselves at the beginning, so we have to analyze the open-source ideas first, which is necessary for our growth.
Currently, the Image cache frameworks that are frequently used include five open-source android components: Universal-Image-Loader, Android-Volley, Picasso, Fresco, and Glide.
First, we should exclude the android-Volley middleware and verify it later. The remaining four ideas on image loading and caching should be similar in a general way.
Android-Universal-Image-Loader, as a classic framework, has been common since the early days, here we will take a look at Android-Universal-Image-Loader's Thoughts on Image processing to help us understand it so that we can write similar frameworks.

For usage configuration, see the usage configuration of Android-Universal-Image-Loader (asynchronously loading cache library for images ).

Body: 1. Workflow

This section describes how to use Android-Universal-Image-Loader in our project.

Before reading it, let's take a look at the official image, which represents the execution process under all conditions:

The image loading process corresponds to three situations:

1. This bitmap is directly displayed in the memory.

2. When the image is stored locally, it is loaded into the memory and displayed.

3. The memory is not available locally. Request the network, download it to the local device, load it into the memory, and then display it.

 

Process Analysis:

 

The display () method in the ImageLoader class is called to display the image. We will focus on the ImageLoader class to see how the display () is implemented internally.

 

Public void displayImage (String uri, ImageAware imageAware, DisplayImageOptions options, ImageLoadingListener, ImageLoadingProgressListener progressListener) {// first check the Initialization configuration, configuration = null throws an exception checkConfiguration (); if (imageAware = null) {throw new IllegalArgumentException (ERROR_WRONG_ARGUMENTS);} if (listener = null) {listener = defaultListener;} if (options = null) {options = configu Ration. 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. get WrappedView (), null); return;} // obtain the image size ImageSize targetSize = ImageSizeUtils Based on the configured size and actual image size. defineTargetSizeForView (imageAware, configuration. getMaxImageSize (); String memoryCacheKey = MemoryCacheUtils. generateKey (uri, targetSize); engine. prepareDisplayTaskFor (imageAware, memoryCacheKey); listener. onLoadingStarted (uri, imageAware. getWrappedView (); // first, it is retrieved from the memory to see if it has been loaded. If there is a cache, Bitmap bmp = configuration is directly used. m EmoryCache. 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) ;}} else {// No cache 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 );}}}

We can see that this method is not long, and the general process is also described in the forward graph:

 

First, determine whether the input target url is "". If it is null, whether the default image is configured. Next, we will focus on loading bitmap when the url is valid. First, we will retrieve it from the memory, check whether it can be obtained (if it is previously loaded to the memory, cached, not removed, it can be obtained). If it is obtained, it can be directly displayed.

 

If it is not obtained in the memory, execute the LoadAndDisplayImageTask task, mainly depending on the execution process of the run () method:

 

@ Overridepublic void run () {if (waitIfPaused () return; if (delayIfNeed () return; 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 () {// No in cache. Download 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) ;}/// cache added to the memory if (bmp! = Null & options. isCacheInMemory () {L. d (LOG_CACHE_IMAGE_IN_MEMORY, memoryCacheKey); // LruMemoryCacheconfiguration. 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 (authorization, memoryCacheKey) ;}} checkTaskNotActual (); checkTaskInterrupted () ;}catch (TaskCancelledException e) {fireCancelEvent (); return ;} finally {loadFromUriLock. unlock ();} DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask (bmp, imageLoadingInfo, engine, loadedFrom); runTask (displayBitmapTask, syncLoading, handler, engine );}

At the beginning, we made some basic judgments, such as whether to pause loading and delayed loading.

 

Next, because the download read/write process is set, a lock is applied to ensure thread security. The download process is not found in the above // cache. The tryLoadBitmap () below this comment () method, what is done in this method, we will be watching it later, now continue to go down, download and get bitmap, then determine whether to add bitmap to the cache in the memory. Finally, set setImageBitmap as the background in the run method of DisplayBitmapTask.

 

This is the general workflow and the three situations mentioned above.

1. In memory, it is displayed directly.

2. The memory is not locally available. It is loaded into the memory and displayed.

3 Local: No, network download, local storage, loaded into memory, and displayed.

 

Next, let's look at the download method tryLoadBitmap () mentioned above. Because it is relatively long, here we only look at the operations in the key try code block:

 

// Check whether the local File contains the cached File imageFile = configuration. diskCache. get (uri); if (imageFile! = Null & imageFile. exists () & imageFile. length ()> 0) {L. d (LOG_LOAD_IMAGE_FROM_DISK_CACHE, memoryCacheKey); loadedFrom = LoadedFrom. DISC_CACHE; checkTaskNotActual (); bitmap = decodeImage (Scheme. FILE. wrap (imageFile. getAbsolutePath ();} // if (bitmap = null | bitmap. getWidth () <= 0 | bitmap. getHeight () <= 0) {L. d (LOG_LOAD_IMAGE_FROM_NETWORK, memoryCacheKey); loadedFrom = LoadedFrom. NETWORK; Stri Ng imageUriForDecoding = uri; if (options. isCacheOnDisk () & tryCacheImageOnDisk () {imageFile = configuration. diskCache. get (uri); if (imageFile! = Null) {imageUriForDecoding = Scheme. FILE. wrap (imageFile. getAbsolutePath () ;}} checkTaskNotActual (); bitmap = decodeImage (imageUriForDecoding );

This is the case above. first look at the local file. If yes, load it into the memory and display it.

 

If no download is available, first determine whether to allow saving to the local device. If yes, download to the local device. Then, use bitmap = decodeImage (imageUriForDecoding) to obtain the target bitmap and return it for display.

 

 

Second, Cache Policy Analysis

We can conclude that UIL adopts two cache policies: memory (memory cache) and local (disk cache.
The benefits of using cache are as follows:
1. Reduce the traffic consumed by each request for network download.
2. reuse is directly obtained from memory/local, improving the loading speed.

 

Next, let's take a look at how UIL caches memory and local files.

By viewing the UIL lib library, we can see that the entire lib mainly consists of three packages.

① Cache: Manage cache ② core: Download core ③ utils: Some auxiliary tools.

You don't need to worry about utils. The remaining two parts are the essence of the entire project: Download display and cache.

Let's take a look at cache first:

It is also composed of two parts: disk and memory.

DiskCache (local cache)

Disc has two types of cache:

The first is the LruDiskCache Based on DiskLruCache, and the second is the LimitedAgeDiskCache and UnlimitedDiskCache Based on BaseDiskCache.

The working principles of these two methods are a little complicated. I will not introduce them here, and I will discuss them in a special opening article.

The similarities between the two methods are to write the requested image inputStream to a local file. The differences are different in fish management methods,

LruDiskCache is automatically deleted based on size> maxSize | fileCount> maxFileCount | or more than 2000 data records.

LimitedAgeDiskCache determines whether to re-download or reuse resources based on the time difference between the storage time and the current time.

UnlimitedDiskCache: the cache size is not limited, as long as there is space on the disk, it can be saved locally.

The above three interfaces all implement the DiskCache interface. The specific working process is save get remove clear and several other methods, similar to the database's curd operation.

 

MemoryCache (memory cache) has many implementation classes for memory caching, all of which implement the MemoryCache interface.
Public interface MemoryCache {/*** Puts value into cache by key * add Value to cache based on Key * @ returnTrue-If value was put into cache successfully,False-If value wasNotPut into * cache */boolean put (String key, Bitmap value);/** Returns value by key. if there is no value for key then null will be returned. */ValueBitmap get (String Key) based on the key;/** Removes item by key */ValueBitmap remove (String Key) based on the key ); /** Returns all keys of cache */Returns all cached KeysCollection
 
  
Keys ();/** Remove all items from cache */mapvoid clear ();}
 

A lot. Let's talk about LruLimitedMemoryCache.
@ Overridepublic boolean put (String key, Bitmap value) {boolean putSuccessfully = false; // Try to add value to hard cache // sizeint valueSize = getSize (value) to be saved ); // The maximum sizeint sizeLimit = getSizeLimit (); // The current size int curCacheSize = cacheSize. get (); // if it is not full, store it in if (valueSize <sizeLimit) {// determine the while (curCacheSize + valueSize> sizeLimit) {Bitmap removedValue = removeNext (); if (hardCache. remove (removedValue) {curCacheSize = cacheSize. addAndGet (-getSize (removedValue) ;}} hardCache. add (value); cacheSize. addAndGet (valueSize); putSuccessfully = true;} // if the value is too large, it is not saved to the above set, and the value is first new WeakReference
 
  
(Value), and then add the Map
  
   
Moderate // Add value to soft cachesuper. put (key, value); return putSuccessfully ;}
  
 
The comment is very detailed. First, you can add the comment to the List to determine the size. In a set such as hardCache, if you can add it to determine whether the current set has exceeded the default maximum value. If the image cannot be added to this set, add the value to WeakReference first. (Value), and then add WeakReference as value to another Map to save.
The conclusion above seems to be hard to understand. The first reading may be messy. Here we will summarize the loading process: Thank you for carefully reading every partner in this article, I sincerely welcome my friends to point out the mistakes in this article and to exchange and learn with me.

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.