前言
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();
}
}
下面逐个来逐个简要说明一下:
taskExecutor
tasks of loading and displaying images
taskExecutorForCachedImages
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本质上就是通过多线程加载图片,然后上述这三个参数都可以配置,一般采用默认值。
diskCache
DefaultConfigurationFactory.createFileNameGenerator();
最后返回的是:String.valueOf(imageUri.hashCode()),ImageLoader在diskcache中存储的文件都是以hashcode编码的。
DefaultConfigurationFactory
.createDiskCache
有兴趣的同学可以自行走读DiskLruCache的实现。
memoryCache
DefaultConfigurationFactory.createMemoryCache(context, memoryCacheSize);
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);
}
默认分配可用内存的1/8。实际通过LruMemoryCache来分配。
他和diskCache类似,都是通过LinkedHashMap来实现lrucache.
当开启.denyCacheImageMultipleSizesInMemory()时
设置拒绝缓存在内存中一个图片多个大小 默认为允许,(同一个图片URL)根据不同大小的imageview保存不同大小图片
memoryCache = new FuzzyKeyMemoryCache(memoryCache, MemoryCacheUtils.createFuzzyKeyComparator());
downloader
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的封装。这块后续再专门描述如何定制。
decoder
最终还是调用bitmapfactory的decodeStream方法进行解压
代码参见:
com.nostra13.universalimageloader.core.decode
decodedBitmap = BitmapFactory.decodeStream(imageStream, null, decodingOptions);
具体的解压参数将在后面的内容中进行说明。
以上就是个人的一些浅解,仅供参考。