publicstaticvoid initImageLoader(Context context) {
File cacheDir = StorageUtils.getOwnCacheDirectory(context,
"bee_k77/Cache");// 获取到缓存的目录地址
Log.e("cacheDir", cacheDir.getPath());
// 创建配置ImageLoader(所有的选项都是可选的,只使用那些你真的想定制),这个可以设定在APPLACATION里面,设置为全局的配置参数
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
context)
// max width, max height,即保存的每个缓存文件的最大长宽
.memoryCacheExtraOptions(480, 800)
// Can slow ImageLoader, use it carefully (Better don't use it)设置缓存的详细信息,最好不要设置这个
/ .discCacheExtraOptions(480, 800, CompressFormat.JPEG, 75, null)
// 线程池内加载的数量
.threadPoolSize(3)
// 线程优先级
.threadPriority(Thread.NORM_PRIORITY - 2)
/*
* When you display an image in a small ImageView
* and later you tryto display this image (from identical URI) in a larger ImageView
* so decoded image of bigger size will be cached in memory as a previous decoded image of smaller size.
* So the default behavior is to allow to cache multiple sizes of one image in memory.
* You can deny it by calling this method:
* so when some image will be cached in memory then previous cached size of this image (if it exists)
* will be removed from memory cache before.
*/
/ .denyCacheImageMultipleSizesInMemory()
// You can pass your own memory cache implementation你可以通过自己的内存缓存实现 // .memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024)) // .memoryCacheSize(2 * 1024 * 1024) //硬盘缓存50MB
.diskCacheSize(50 * 1024 * 1024)
//将保存的时候的URI名称用MD5
.diskCacheFileNameGenerator(new Md5FileNameGenerator())
// 加密
.diskCacheFileNameGenerator(new HashCodeFileNameGenerator())//将保存的时候的URI名称用HASHCODE加密
.tasksProcessingOrder(QueueProcessingType.LIFO)
.diskCacheFileCount(100) //缓存的File数量
.diskCache(new UnlimitedDiscCache(cacheDir))// 自定义缓存路径 // .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // .imageDownloader(new BaseImageDownloader(context, 5 * 1000, // 30 * 1000)) // connectTimeout (5 s), readTimeout (30 s)超时时间
.writeDebugLogs() // Remove for release app
.build();
// Initialize ImageLoader with configuration.
ImageLoader.getInstance().init(config);// 全局初始化此配置
}
我们可以清楚看到建造者模式和链式调用的身影,接下来我们来看一下源码的实现。
publicfinalclassImageLoaderConfiguration {final Resources resources;
finalint maxImageWidthForMemoryCache;//finalint maxImageHeightForMemoryCache;
finalint maxImageWidthForDiskCache;//最大图片finalint maxImageHeightForDiskCache;
final BitmapProcessor processorForDiskCache;
final Executor taskExecutor;
final Executor taskExecutorForCachedImages;
finalboolean customExecutor;
finalboolean customExecutorForCachedImages;
finalint threadPoolSize;
finalint threadPriority;
final QueueProcessingType tasksProcessingType;
final MemoryCache memoryCache;
final DiskCache diskCache;
final ImageDownloader downloader;
final ImageDecoder decoder;
final DisplayImageOptions defaultDisplayImageOptions;
final ImageDownloader networkDeniedDownloader;
final ImageDownloader slowNetworkDownloader;
privateImageLoaderConfiguration(final Builder builder) {
resources = builder.context.getResources();
maxImageWidthForMemoryCache = builder.maxImageWidthForMemoryCache;
maxImageHeightForMemoryCache = builder.maxImageHeightForMemoryCache;
maxImageWidthForDiskCache = builder.maxImageWidthForDiskCache;
maxImageHeightForDiskCache = builder.maxImageHeightForDiskCache;
processorForDiskCache = builder.processorForDiskCache;
taskExecutor = builder.taskExecutor;
taskExecutorForCachedImages = builder.taskExecutorForCachedImages;
threadPoolSize = builder.threadPoolSize;
threadPriority = builder.threadPriority;
tasksProcessingType = builder.tasksProcessingType;
diskCache = builder.diskCache;
memoryCache = builder.memoryCache;
defaultDisplayImageOptions = builder.defaultDisplayImageOptions;
downloader = builder.downloader;
decoder = builder.decoder;
customExecutor = builder.customExecutor;
customExecutorForCachedImages = builder.customExecutorForCachedImages;
networkDeniedDownloader = new NetworkDeniedImageDownloader(downloader);
slowNetworkDownloader = new SlowNetworkImageDownloader(downloader);
}
/**
* 初始化一个空
*/publicstatic ImageLoaderConfiguration createDefault(Context context) {
returnnew Builder(context).build();
}
ImageSize getMaxImageSize() {
DisplayMetrics displayMetrics = resources.getDisplayMetrics();
int width = maxImageWidthForMemoryCache;
if (width <= 0) {
width = displayMetrics.widthPixels;
}
int height = maxImageHeightForMemoryCache;
if (height <= 0) {
height = displayMetrics.heightPixels;
}
returnnew ImageSize(width, height);
}
/**
* Builder for {@link ImageLoaderConfiguration}
*
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
*/publicstaticclassBuilder {privatestaticfinal String WARNING_OVERLAP_DISK_CACHE_PARAMS = "diskCache(), diskCacheSize() and diskCacheFileCount calls overlap each other";
privatestaticfinal String WARNING_OVERLAP_DISK_CACHE_NAME_GENERATOR = "diskCache() and diskCacheFileNameGenerator() calls overlap each other";
privatestaticfinal String WARNING_OVERLAP_MEMORY_CACHE = "memoryCache() and memoryCacheSize() calls overlap each other";
privatestaticfinal String WARNING_OVERLAP_EXECUTOR = "threadPoolSize(), threadPriority() and tasksProcessingOrder() calls "
+ "can overlap taskExecutor() and taskExecutorForCachedImages() calls.";
/**
* {@value}
*/publicstaticfinalint DEFAULT_THREAD_POOL_SIZE = 3;
/**
* {@value}
*/publicstaticfinalint DEFAULT_THREAD_PRIORITY = Thread.NORM_PRIORITY - 2;
/**
* {@value}
*/publicstaticfinal QueueProcessingType DEFAULT_TASK_PROCESSING_TYPE = QueueProcessingType.FIFO;
private Context context;
privateint maxImageWidthForMemoryCache = 0;
privateint maxImageHeightForMemoryCache = 0;
privateint maxImageWidthForDiskCache = 0;
privateint maxImageHeightForDiskCache = 0;
private BitmapProcessor processorForDiskCache = null;
private Executor taskExecutor = null;
private Executor taskExecutorForCachedImages = null;
privateboolean customExecutor = false;
privateboolean customExecutorForCachedImages = false;
privateint threadPoolSize = DEFAULT_THREAD_POOL_SIZE;
privateint threadPriority = DEFAULT_THREAD_PRIORITY;
privateboolean denyCacheImageMultipleSizesInMemory = false;
private QueueProcessingType tasksProcessingType = DEFAULT_TASK_PROCESSING_TYPE;
privateint memoryCacheSize = 0;
privatelong diskCacheSize = 0;
privateint diskCacheFileCount = 0;
private MemoryCache memoryCache = null;
private DiskCache diskCache = null;
private FileNameGenerator diskCacheFileNameGenerator = null;
private ImageDownloader downloader = null;
private ImageDecoder decoder;
private DisplayImageOptions defaultDisplayImageOptions = null;
privateboolean writeLogs = false;
publicBuilder(Context context) {
this.context = context.getApplicationContext();
}
/**即保存的每个缓存文件的最大长宽
*/public Builder memoryCacheExtraOptions(int maxImageWidthForMemoryCache, int maxImageHeightForMemoryCache) {
this.maxImageWidthForMemoryCache = maxImageWidthForMemoryCache;
this.maxImageHeightForMemoryCache = maxImageHeightForMemoryCache;
returnthis;
}
/**
*/@Deprecatedpublic Builder discCacheExtraOptions(int maxImageWidthForDiskCache, int maxImageHeightForDiskCache,
BitmapProcessor processorForDiskCache) {
return diskCacheExtraOptions(maxImageWidthForDiskCache, maxImageHeightForDiskCache, processorForDiskCache);
}
/**
*/public Builder diskCacheExtraOptions(int maxImageWidthForDiskCache, int maxImageHeightForDiskCache,
BitmapProcessor processorForDiskCache) {
this.maxImageWidthForDiskCache = maxImageWidthForDiskCache;
this.maxImageHeightForDiskCache = maxImageHeightForDiskCache;
this.processorForDiskCache = processorForDiskCache;
returnthis;
}
/**
*/public Builder taskExecutor(Executor executor) {
if (threadPoolSize != DEFAULT_THREAD_POOL_SIZE || threadPriority != DEFAULT_THREAD_PRIORITY || tasksProcessingType != DEFAULT_TASK_PROCESSING_TYPE) {
}
this.taskExecutor = executor;
returnthis;
}
/**
*/public Builder taskExecutorForCachedImages(Executor executorForCachedImages) {
if (threadPoolSize != DEFAULT_THREAD_POOL_SIZE || threadPriority != DEFAULT_THREAD_PRIORITY || tasksProcessingType != DEFAULT_TASK_PROCESSING_TYPE) {
}
this.taskExecutorForCachedImages = executorForCachedImages;
returnthis;
}
/**
* // 线程池内加载的数量
*/public Builder threadPoolSize(int threadPoolSize) {
if (taskExecutor != null || taskExecutorForCachedImages != null) {
}
this.threadPoolSize = threadPoolSize;
returnthis;
}
/**
// 线程优先级
*/public Builder threadPriority(int threadPriority) {
if (taskExecutor != null || taskExecutorForCachedImages != null) {
}
if (threadPriority < Thread.MIN_PRIORITY) {
this.threadPriority = Thread.MIN_PRIORITY;
} else {
if (threadPriority > Thread.MAX_PRIORITY) {
this.threadPriority = Thread.MAX_PRIORITY;
} else {
this.threadPriority = threadPriority;
}
}
returnthis;
}
/**
*/public Builder denyCacheImageMultipleSizesInMemory() {
this.denyCacheImageMultipleSizesInMemory = true;
returnthis;
}
/**
* 设置处理队列类型
* Default value - {@link QueueProcessingType#FIFO}
*/public Builder tasksProcessingOrder(QueueProcessingType tasksProcessingType) {
if (taskExecutor != null || taskExecutorForCachedImages != null) {
}
this.tasksProcessingType = tasksProcessingType;
returnthis;
}
/**
*/public Builder memoryCacheSize(int memoryCacheSize) {
if (memoryCacheSize <= 0)
thrownew IllegalArgumentException("memoryCacheSize must be a positive number");
if (memoryCache != null) {
}
this.memoryCacheSize = memoryCacheSize;
returnthis;
}
/**
* Sets maximum memory cache size (in percent of available app memory) for {@link android.graphics.Bitmap
* bitmaps}.<br />
* Default value - 1/8 of available app memory.<br />
* <b>NOTE:</b> If you use this method then
* memory cache. You can use {@link #memoryCache(MemoryCache)} method to set your own implementation of
* {@link MemoryCache}.
*/public Builder memoryCacheSizePercentage(int availableMemoryPercent) {
if (availableMemoryPercent <= 0 || availableMemoryPercent >= 100) {
thrownew IllegalArgumentException("availableMemoryPercent must be in range (0 < % < 100)");
}
if (memoryCache != null) {
}
long availableMemory = Runtime.getRuntime().maxMemory();
memoryCacheSize = (int) (availableMemory * (availableMemoryPercent / 100f));
returnthis;
}
/**
* Sets memory cache for {@link android.graphics.Bitmap bitmaps}.<br />
* with limited memory cache size (size = 1/8 of available app memory)<br />
* <br />
* <b>NOTE:</b> If you set custom memory cache then following configuration option will not be considered:
* <ul>
* <li>{@link #memoryCacheSize(int)}</li>
* </ul>
*/public Builder memoryCache(MemoryCache memoryCache) {
if (memoryCacheSize != 0) {
}
this.memoryCache = memoryCache;
returnthis;
}
/**
//硬盘缓存50MB
*/@Deprecatedpublic Builder discCacheSize(int maxCacheSize) {
return diskCacheSize(maxCacheSize);
}
/**
*/public Builder diskCacheSize(int maxCacheSize) {
if (maxCacheSize <= 0)
thrownew IllegalArgumentException("maxCacheSize must be a positive number");
if (diskCache != null) {
}
this.diskCacheSize = maxCacheSize;
returnthis;
}
/**
* @deprecated Use {@link #diskCacheFileCount(int)} instead
*/@Deprecatedpublic Builder discCacheFileCount(int maxFileCount) {
return diskCacheFileCount(maxFileCount);
}
/**
* Sets maximum file count in disk cache directory.<br />
* By default: disk cache is unlimited.<br />
* <b>NOTE:</b> If you use this method then
* will be used as disk cache. You can use {@link #diskCache(DiskCache)} method for introduction your own
* implementation of {@link DiskCache}
*/public Builder diskCacheFileCount(int maxFileCount) {
if (maxFileCount <= 0)
thrownew IllegalArgumentException("maxFileCount must be a positive number");
if (diskCache != null) {
}
this.diskCacheFileCount = maxFileCount;
returnthis;
}
/** //将保存的时候的URI名称用MD5
*/@Deprecatedpublic Builder discCacheFileNameGenerator(FileNameGenerator fileNameGenerator) {
return diskCacheFileNameGenerator(fileNameGenerator);
}
/**
* Sets name generator for files cached in disk cache.<br />
* Default value -
* DefaultConfigurationFactory.createFileNameGenerator()}
*/public Builder diskCacheFileNameGenerator(FileNameGenerator fileNameGenerator) {
if (diskCache != null) {
}
this.diskCacheFileNameGenerator = fileNameGenerator;
returnthis;
}
/**
*/@Deprecatedpublic Builder discCache(DiskCache diskCache) {
return diskCache(diskCache);
}
/**
设置磁盘缓存策略
*/public Builder diskCache(DiskCache diskCache) {
if (diskCacheSize > 0 || diskCacheFileCount > 0) {
}
if (diskCacheFileNameGenerator != null) {
}
this.diskCache = diskCache;
returnthis;
}
/**
设置图片下载器
*/public Builder imageDownloader(ImageDownloader imageDownloader) {
this.downloader = imageDownloader;
returnthis;
}
/**
设置图片展示器
*/public Builder imageDecoder(ImageDecoder imageDecoder) {
this.decoder = imageDecoder;
returnthis;
}
/**
设置默认的图片展示操作参数
*/public Builder defaultDisplayImageOptions(DisplayImageOptions defaultDisplayImageOptions) {
this.defaultDisplayImageOptions = defaultDisplayImageOptions;
returnthis;
}
/**是否写日志
*/public Builder writeDebugLogs() {
this.writeLogs = true;
returnthis;
}
/**
* Builds configured {@link ImageLoaderConfiguration} object
*/public ImageLoaderConfiguration build() {
initEmptyFieldsWithDefaultValues();
returnnew ImageLoaderConfiguration(this);
}
privatevoidinitEmptyFieldsWithDefaultValues() {
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();
}
}
}
/**
网络图片下载器
*/privatestaticclassNetworkDeniedImageDownloaderimplementsImageDownloader {privatefinal ImageDownloader wrappedDownloader;
publicNetworkDeniedImageDownloader(ImageDownloader wrappedDownloader) {
this.wrappedDownloader = wrappedDownloader;
}
@Overridepublic InputStream getStream(String imageUri, Object extra) throws IOException {
switch (Scheme.ofUri(imageUri)) {
case HTTP:
case HTTPS:
thrownew IllegalStateException();
default:
return wrappedDownloader.getStream(imageUri, extra);
}
}
}
/**
* 网络慢的时候使用一个流刷
*/privatestaticclassSlowNetworkImageDownloaderimplementsImageDownloader {privatefinal ImageDownloader wrappedDownloader;
publicSlowNetworkImageDownloader(ImageDownloader wrappedDownloader) {
this.wrappedDownloader = wrappedDownloader;
}
@Overridepublic InputStream getStream(String imageUri, Object extra) throws IOException {
InputStream imageStream = wrappedDownloader.getStream(imageUri, extra);
switch (Scheme.ofUri(imageUri)) {
case HTTP:
case HTTPS:
returnnew FlushedInputStream(imageStream);
default:
return imageStream;
}
}
}
}
(6)ImageLoaderEngine
这是一个负责将图片加载任务分发到各个线程执行的类
/*******************************************************************************
* Copyright 2011-2014 Sergey Tarasevich
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/package leakcanary.imageloader.core;
import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
import leakcanary.imageloader.core.imageaware.ImageAware;
/**
*负责将图片加载任务分发到各个线程执行。
*/
class ImageLoaderEngine {
final ImageLoaderConfiguration configuration;//配置信息private Executor taskExecutor;//执行从源获取图片任务的executorprivate Executor taskExecutorForCachedImages;//执行从缓存获取图片任务的executorprivate Executor taskDistributor;//任务分发池privatefinal Map<Integer, String> cacheKeysForImageAwares = Collections
.synchronizedMap(new HashMap<Integer, String>());
privatefinal Map<String, ReentrantLock> uriLocks = new WeakHashMap<String, ReentrantLock>();
privatefinal AtomicBoolean paused = new AtomicBoolean(false);//是否暂停执行任务privatefinal AtomicBoolean networkDenied = new AtomicBoolean(false);//是否拒绝网络访问privatefinal AtomicBoolean slowNetwork = new AtomicBoolean(false);//是否是慢网络情况privatefinal Object pauseLock = new Object();//暂停等待锁//初始化
ImageLoaderEngine(ImageLoaderConfiguration configuration) {
this.configuration = configuration;
taskExecutor = configuration.taskExecutor;
taskExecutorForCachedImages = configuration.taskExecutorForCachedImages;
taskDistributor = DefaultConfigurationFactory.createTaskDistributor();
}
//提交LoadAndDisplayImageTask任务void submit(final LoadAndDisplayImageTask task) {
taskDistributor.execute(new Runnable() {
@Overridepublicvoidrun() {
File image = configuration.diskCache.get(task.getLoadingUri());
boolean isImageCachedOnDisk = image != null && image.exists();
initExecutorsIfNeed();
if (isImageCachedOnDisk) {
taskExecutorForCachedImages.execute(task);
} else {
taskExecutor.execute(task);
}
}
});
}
/** 直接交由taskExecutorForCachedImages执行。 */void submit(ProcessAndDisplayImageTask task) {
initExecutorsIfNeed();
taskExecutorForCachedImages.execute(task);
}
privatevoidinitExecutorsIfNeed() {
if (!configuration.customExecutor && ((ExecutorService) taskExecutor).isShutdown()) {
taskExecutor = createTaskExecutor();
}
if (!configuration.customExecutorForCachedImages && ((ExecutorService) taskExecutorForCachedImages)
.isShutdown()) {
taskExecutorForCachedImages = createTaskExecutor();
}
}
private Executor createTaskExecutor() {
return DefaultConfigurationFactory
.createExecutor(configuration.threadPoolSize, configuration.threadPriority,
configuration.tasksProcessingType);
}
/**
*/
String getLoadingUriForView(ImageAware imageAware) {
return cacheKeysForImageAwares.get(imageAware.getId());
}
/**
* Associates <b>memoryCacheKey</b> with <b>imageAware</b>. Then it helps to define image URI is loaded into View at
* exact moment.
*/void prepareDisplayTaskFor(ImageAware imageAware, String memoryCacheKey) {
cacheKeysForImageAwares.put(imageAware.getId(), memoryCacheKey);
}
/**
* Cancels the task of loading and displaying image for incoming <b>imageAware</b>.
*
* will be cancelled
*/void cancelDisplayTaskFor(ImageAware imageAware) {
cacheKeysForImageAwares.remove(imageAware.getId());
}
/**
* Denies or allows engine to download images from the network.<br /> <br /> If downloads are denied and if image
*
* @param denyNetworkDownloads pass <b>true</b> - to deny engine to download images from the network; <b>false</b> -
* to allow engine to download images from network.
*/void denyNetworkDownloads(boolean denyNetworkDownloads) {
networkDenied.set(denyNetworkDownloads);
}
/**
* href="http://code.google.com/p/android/issues/detail?id=6066">this known problem</a> or not.
*
* - otherwise.
*/void handleSlowNetwork(boolean handleSlowNetwork) {
slowNetwork.set(handleSlowNetwork);
}
/**
* Pauses engine. All new "load&display" tasks won't be executed until ImageLoader is {@link #resume() resumed}.<br
* /> Already running tasks are not paused.
*/void pause() {
paused.set(true);
}
/** Resumes engine work. Paused "load&display" tasks will continue its work. */void resume() {
paused.set(false);
synchronized (pauseLock) {
pauseLock.notifyAll();
}
}
/**
* Stops engine, cancels all running and scheduled display image tasks. Clears internal data.
* <br />
* <b>NOTE:</b> This method doesn't shutdown
* custom task executors} if you set them.
*/void stop() {
if (!configuration.customExecutor) {
((ExecutorService) taskExecutor).shutdownNow();
}
if (!configuration.customExecutorForCachedImages) {
((ExecutorService) taskExecutorForCachedImages).shutdownNow();
}
cacheKeysForImageAwares.clear();
uriLocks.clear();
}
void fireCallback(Runnable r) {
taskDistributor.execute(r);
}
ReentrantLock getLockForUri(String uri) {
ReentrantLock lock = uriLocks.get(uri);
if (lock == null) {
lock = new ReentrantLock();
uriLocks.put(uri, lock);
}
return lock;
}
AtomicBoolean getPause() {
return paused;
}
Object getPauseLock() {
return pauseLock;
}
boolean isNetworkDenied() {
return networkDenied.get();
}
boolean isSlowNetwork() {
return slowNetwork.get();
}
}
//图片缩放的类型publicenum ViewScaleType {
FIT_INSIDE,
CROP;
//判断类型publicstatic ViewScaleType fromImageView(ImageView imageView) {
switch (imageView.getScaleType()) {
case FIT_CENTER:
case FIT_XY:
case FIT_START:
case FIT_END:
case CENTER_INSIDE:
return FIT_INSIDE;
case MATRIX:
case CENTER:
case CENTER_CROP:
default:
return CROP;
}
}
}
/**
* Queue processing type which will be used for display task processing
* 请求队列的处理类型
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
* @since 1.6.3
*/publicenum QueueProcessingType {
FIFO, LIFO
}