Universal-Image-Loader Source Code Analysis (I) - Image Loader Configuration Analysis

Posted by rikmoncur on Fri, 14 Jun 2019 01:45:17 +0200

UIL, like Volley, is a very old framework. UIL implements the acquisition of pictures from the network, the caching of pictures, and the loading of pictures to ImageView according to personalized settings.

This article mainly analyses the source code of UIl in initialization configuration.

Source code analysis for UIL initialization

UIl provides the initialization operation of UIl in Application. The common initialization operation codes are as follows:

    ImageLoaderConfiguration.Builder config = new ImageLoaderConfiguration.Builder(context);
        config.threadPriority(Thread.NORM_PRIORITY - 2);
        config.denyCacheImageMultipleSizesInMemory();
        config.diskCacheFileNameGenerator(new Md5FileNameGenerator());
        config.diskCacheSize(50 * 1024 * 1024); // 50 MiB
        config.tasksProcessingOrder(QueueProcessingType.LIFO);
        config.writeDebugLogs(); // Remove for release app

        // Initialize ImageLoader with configuration.
        ImageLoader.getInstance().init(config.build());

Builder pattern to build Image Loader Configuration.
The following are the member variables of the ImageLoaderConfiguration class, as well as the specific configuration options.

    
    //resource information
    final Resources resources;
    //Maximum Width of Memory Cached Pictures
    final int maxImageWidthForMemoryCache;
    //Maximum Height of Memory Cached Pictures
    final int maxImageHeightForMemoryCache;
    //Maximum Width of Cached Pictures in Local File System
    final int maxImageWidthForDiskCache;
    //Maximum height of cached images in local file system
    final int maxImageHeightForDiskCache;
    //Local File System Cached Picture Processor
    final BitmapProcessor processorForDiskCache;
    //Task executor
    final Executor taskExecutor;
    //Image Cache Task Executor
    final Executor taskExecutorForCachedImages;
    //Whether to customize task executors
    final boolean customExecutor;
    //Whether to customize task Executors for image caching
    final boolean customExecutorForCachedImages;
    //Number of threads in thread pool
    final int threadPoolSize;
    //Thread level
    final int threadPriority;
    //Types of Processing Algorithms in Queues
    final QueueProcessingType tasksProcessingType;
    //Memory cache object
    final MemoryCache memoryCache;
    //Local File System Cache Objects
    final DiskCache diskCache;
    //Image default download loader
    final ImageDownloader downloader;
    //Picture decoder
    final ImageDecoder decoder;
    //Picture Display Configuration Parameters
    final DisplayImageOptions defaultDisplayImageOptions;
    //Downloader in Network Denial
    final ImageDownloader networkDeniedDownloader;
    //Downloader for Slow Network
    final ImageDownloader slowNetworkDownloader;

Builder pattern builds objects, many of the variables mentioned above are imported through the outside. We only look at the initial values of a few variables.

  • The default number of threads in the thread pool is 3
  • Thread's priority is Thread.NORM_PRIORITY - 2
  • The queue processing algorithm is QueueProcessingType.FIFO

If config is not specified, the default configuration is used to create a series of initialization values through factory mode.
The initial values created are as follows:

  • taskExecutor
  • taskExecutorForCachedImages
  • diskCache
  • memoryCache
  • downloader
  • decoder

Let's look at the source code for Default Configuration Factory

The default configuration factory class creates task executors taskExecutor, taskExecutor ForCachedImages

public static Executor createExecutor(int threadPoolSize, int threadPriority,
            QueueProcessingType tasksProcessingType) {
        //Initialization queue algorithm type defaults to LIFO
        boolean lifo = tasksProcessingType == QueueProcessingType.LIFO;
        //Initialization queues create different queues according to different algorithm types
        BlockingQueue<Runnable> taskQueue =
                lifo ? new LIFOLinkedBlockingDeque<Runnable>() : new LinkedBlockingQueue<Runnable>();
        return new ThreadPoolExecutor(threadPoolSize, threadPoolSize, 0L, TimeUnit.MILLISECONDS, taskQueue,
                createThreadFactory(threadPriority, "uil-pool-"));
    }

The main thing is to create blocking queues, and create various types of blocking queues according to the type of QueueProcessing Type.
When executing this method, FIFO is in Image Loader Configuration if we do not specify it, FIFO is first in first out.
TaskExecutor and taskExecutor ForCachedImages have the same initialization method and parameters

Let's look at the initialization of various caches

For DiskCache, the code is as follows:

public static DiskCache createDiskCache(Context context, FileNameGenerator diskCacheFileNameGenerator,
            long diskCacheSize, int diskCacheFileCount) {
        //Create an alternate cache file
        File reserveCacheDir = createReserveDiskCacheDir(context);
        if (diskCacheSize > 0 || diskCacheFileCount > 0) {
            File individualCacheDir = StorageUtils.getIndividualCacheDirectory(context);
            try {
                //Create a local file system cache
                return new LruDiskCache(individualCacheDir, reserveCacheDir, diskCacheFileNameGenerator, diskCacheSize,
                        diskCacheFileCount);
            } catch (IOException e) {
                L.e(e);
                // continue and create unlimited cache
            }
        }
        //Create an unlimited file buffer
        File cacheDir = StorageUtils.getCacheDirectory(context);
        return new UnlimitedDiskCache(cacheDir, reserveCacheDir, diskCacheFileNameGenerator);
    }

This shows that when LruDiskCache is not available, an unlimited file cache is created.

For MemoryCache, the code is as follows:

public static MemoryCache createMemoryCache(Context context, int memoryCacheSize) {
        if (memoryCacheSize == 0) {
            ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
            int memoryClass = am.getMemoryClass();
            if (hasHoneycomb() && isLargeHeap(context)) {
                memoryClass = getLargeMemoryClass(am);
            }
            memoryCacheSize = 1024 * 1024 * memoryClass / 8;
        }
        return new LruMemoryCache(memoryCacheSize);
    }

memoryCacheSize is the limited memory size of each App, and memoryCache is one-eighth of the limited memory size of App.

The default configuration factory also creates the default Image Downloader BaseIamge Downloader and the default image decoder BaseImageDecoder.
Let's analyze this later.

So far, various configurations of UIL initialization have been completed. In the next article, we will take a look at the internal process of UIL initialization when it is used.

Topics: Android network