Universal-ImageLoader是一个开源的图片加载框架。 希望能通过走读源码流程的方式,了解图片加载的方式方法。
ImageLoader的实例创建。
public static ImageLoader getInstance() { if (instance == null) { synchronized (ImageLoader.class) { if (instance == null) { instance = new ImageLoader(); } } } return instance; }在实际的应用中,ImageLoader在app中创建,伴随整个app的生命周期,这是一个单例,通过该单例来进行相关的操作。
ImageLoader.getInstance().init(config); public synchronized void init(ImageLoaderConfiguration configuration) { if (configuration == null) { throw new IllegalArgumentException(ERROR_INIT_CONFIG_WITH_NULL); } if (this.configuration == null) { L.d(LOG_INIT_CONFIG); engine = new ImageLoaderEngine(configuration); this.configuration = configuration; } else { L.w(WARNING_RE_INIT_CONFIG); } }这次我们先来看一下init的可配参数有哪些,具体又是如何进行配置的。 从上面的代码可以看到配置是一个ImageLoaderConfiguration的类,通常的配置的内容可以有哪些呢?
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getAppContext()) .denyCacheImageMultipleSizesInMemory() .memoryCache(new WeakMemoryCache()) .diskCache(new UnlimitedDiskCache(cacheDir)) .memoryCacheSize(20 * 1024 * 1024) .diskCacheSize(200 * 1024 * 1024) .diskCacheFileCount(1000) .writeDebugLogs() .build();ImageLoaderConfiguration是一个典型的以builder模式设计的类,具体参数的创建方法见下面的源码。
private void initEmptyFieldsWithDefaultValues() { if (taskExecutor == null) { taskExecutor = DefaultConfigurationFactory .createExecutor(threadPoolSize, threadPriority, tasksProcessingType); } else { customExecutor = true; } if (taskExecutorForCachedImages == null) { taskExecutorForCachedImages = DefaultConfigurationFactory .createExecutor(threadPoolSize, threadPriority, tasksProcessingType); } else { customExecutorForCachedImages = true; } if (diskCache == null) { if (diskCacheFileNameGenerator == null) { diskCacheFileNameGenerator = DefaultConfigurationFactory.createFileNameGenerator(); } diskCache = DefaultConfigurationFactory .createDiskCache(context, diskCacheFileNameGenerator, diskCacheSize, diskCacheFileCount); } if (memoryCache == null) { memoryCache = DefaultConfigurationFactory.createMemoryCache(context, memoryCacheSize); } if (denyCacheImageMultipleSizesInMemory) { memoryCache = new FuzzyKeyMemoryCache(memoryCache, MemoryCacheUtils.createFuzzyKeyComparator()); } if (downloader == null) { downloader = DefaultConfigurationFactory.createImageDownloader(context); } if (decoder == null) { decoder = DefaultConfigurationFactory.createImageDecoder(writeLogs); } if (defaultDisplayImageOptions == null) { defaultDisplayImageOptions = DisplayImageOptions.createSimple(); } }tasks of loading and displaying images
tasks of displaying cached on disk images
DefaultConfigurationFactory .createExecutor 源码:
public static Executor createExecutor(int threadPoolSize, int threadPriority, QueueProcessingType tasksProcessingType) { boolean lifo = tasksProcessingType == QueueProcessingType.LIFO; BlockingQueue<Runnable> taskQueue = lifo ? new LIFOLinkedBlockingDeque<Runnable>() : new LinkedBlockingQueue<Runnable>(); return new ThreadPoolExecutor(threadPoolSize, threadPoolSize, 0L, TimeUnit.MILLISECONDS, taskQueue, createThreadFactory(threadPriority, "uil-pool-")); }相关的默认参数: /* {@value} / public static final int DEFAULT_THREAD_POOL_SIZE = 3; /* {@value} / public static final int DEFAULT_THREAD_PRIORITY = Thread.NORM_PRIORITY - 2; /* {@value} / public static final QueueProcessingType DEFAULT_TASK_PROCESSING_TYPE = QueueProcessingType.FIFO; 从这里可以看到ImageLoader本质上就是通过多线程加载图片,然后上述这三个参数都可以配置,一般采用默认值。
DefaultConfigurationFactory.createFileNameGenerator(); 最后返回的是:String.valueOf(imageUri.hashCode()),ImageLoader在diskcache中存储的文件都是以hashcode编码的。 DefaultConfigurationFactory .createDiskCache 有兴趣的同学可以自行走读DiskLruCache的实现。
默认分配可用内存的1/8。实际通过LruMemoryCache来分配。 他和diskCache类似,都是通过LinkedHashMap来实现lrucache. 当开启.denyCacheImageMultipleSizesInMemory()时 设置拒绝缓存在内存中一个图片多个大小 默认为允许,(同一个图片URL)根据不同大小的imageview保存不同大小图片
memoryCache = new FuzzyKeyMemoryCache(memoryCache, MemoryCacheUtils.createFuzzyKeyComparator());Provides retrieving of {@link InputStream} of image by URI from network or file system or app resources. 下载器,具体可以看 com.nostra13.universalimageloader.core.download下的两个文件。 imageloader的downloader比较老,这块不如picasso直接使用okhttp的封装。这块后续再专门描述如何定制。
最终还是调用bitmapfactory的decodeStream方法进行解压 代码参见: com.nostra13.universalimageloader.core.decode
decodedBitmap = BitmapFactory.decodeStream(imageStream, null, decodingOptions);具体的解压参数将在后面的内容中进行说明。
以上就是个人的一些浅解,仅供参考。
