/** * Sets disc cache for images.<br> * Default value - {@link com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache * UnlimitedDiscCache}. Cache directory is defined by <b> {@link * com.nostra13.universalimageloader.utils.StorageUtils#getCacheDirectory(Context) * StorageUtils.getCacheDirectory(Context)}.<br> */ public Builder discCache(DiscCacheAware discCache) { if (discCacheSize > 0) L.w(WARNING_OVERLAP_DISC_CACHE_SIZE); if (discCacheFileCount > 0) L.w(WARNING_OVERLAP_DISC_CACHE_FILE_COUNT); if (discCacheFileNameGenerator != null) L.w(WARNING_OVERLAP_DISC_CACHE_FILE_NAME_GENERATOR); this.discCache = discCache; return this; }
/** * Sets maximum disc cache size for images (in bytes).<br> * By default: disc cache is unlimited.<br> * <b>NOTE:</b> If you use this method then {@link * com.nostra13.universalimageloader.cache.disc.impl.TotalSizeLimitedDiscCache * TotalSizeLimitedDiscCache} will be used as disc cache. You can use {@link * #discCache(DiscCacheAware)} method for introduction your own implementation of {@link * DiscCacheAware} */ public Builder discCacheSize(int maxCacheSize) { if (maxCacheSize <= 0) throw new IllegalArgumentException("maxCacheSize must be a positive number"); if (discCache != null) L.w(WARNING_DISC_CACHE_ALREADY_SET); if (discCacheFileCount > 0) L.w(WARNING_OVERLAP_DISC_CACHE_FILE_COUNT); this.discCacheSize = maxCacheSize; return this; }
/** * Sets maximum file count in disc cache directory.<br> * By default: disc cache is unlimited.<br> * <b>NOTE:</b> If you use this method then {@link * com.nostra13.universalimageloader.cache.disc.impl.FileCountLimitedDiscCache * FileCountLimitedDiscCache} will be used as disc cache. You can use {@link * #discCache(DiscCacheAware)} method for introduction your own implementation of {@link * DiscCacheAware} */ public Builder discCacheFileCount(int maxFileCount) { if (maxFileCount <= 0) throw new IllegalArgumentException("maxFileCount must be a positive number"); if (discCache != null) L.w(WARNING_DISC_CACHE_ALREADY_SET); if (discCacheSize > 0) L.w(WARNING_OVERLAP_DISC_CACHE_SIZE); this.discCacheSize = 0; this.discCacheFileCount = maxFileCount; return this; }
/** * 设置本地文件系统缓存器 Sets disk cache for images.<br> * Default value - {@link com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache * UnlimitedDiskCache}. Cache directory is defined by {@link * com.nostra13.universalimageloader.utils.StorageUtils#getCacheDirectory(Context) * StorageUtils.getCacheDirectory(Context)}.<br> * <br> * <b>NOTE:</b> If you set custom disk cache then following configuration option will not be * considered: * * <ul> * <li>{@link #diskCacheSize(int)} * <li>{@link #diskCacheFileCount(int)} * <li>{@link #diskCacheFileNameGenerator(FileNameGenerator)} * </ul> */ public Builder diskCache(DiskCache diskCache) { if (diskCacheSize > 0 || diskCacheFileCount > 0) { L.w(WARNING_OVERLAP_DISK_CACHE_PARAMS); } if (diskCacheFileNameGenerator != null) { L.w(WARNING_OVERLAP_DISK_CACHE_NAME_GENERATOR); } this.diskCache = diskCache; return this; }
public diskCacheSize diskCache(DiskCache diskcache) { if (diskCacheSize > 0L || diskCacheFileCount > 0) { L.w("diskCache(), diskCacheSize() and diskCacheFileCount calls overlap each other", new Object[0]); } if (diskCacheFileNameGenerator != null) { L.w("diskCache() and diskCacheFileNameGenerator() calls overlap each other", new Object[0]); } diskCache = diskcache; return this; }
/** * Initializes ImageLoader instance with configuration.<br> * If configurations was set before ( {@link #isInited()} == true) then this method does nothing. * <br> * To force initialization with new configuration you should {@linkplain #destroy() destroy * ImageLoader} at first. * * @param configuration {@linkplain ImageLoaderConfiguration ImageLoader configuration} * @throws IllegalArgumentException if <b>configuration</b> parameter is null */ public synchronized void init( ImageLoaderConfiguration configuration, ImageTokenCallback tokenCallback) { if (configuration == null) { throw new IllegalArgumentException(ERROR_INIT_CONFIG_WITH_NULL); } this.tokenCallback = tokenCallback; if (this.configuration == null) { L.d(LOG_INIT_CONFIG); engine = new ImageLoaderEngine(configuration); this.configuration = configuration; } else { L.w(WARNING_RE_INIT_CONFIG); } }
private Bitmap tryLoadBitmap() { DiscCacheAware discCache = configuration.discCache; File imageFile = discCache.get(uri); Bitmap bitmap = null; try { // Try to load image from disc cache if (imageFile.exists()) { log(LOG_LOAD_IMAGE_FROM_DISC_CACHE, memoryCacheKey); Bitmap b = decodeImage(imageFile.toURI()); if (b != null) { return b; } } // Load image from Web log(LOG_LOAD_IMAGE_FROM_INTERNET, memoryCacheKey); URI imageUriForDecoding; if (options.isCacheOnDisc()) { log(LOG_CACHE_IMAGE_ON_DISC, memoryCacheKey); saveImageOnDisc(imageFile); discCache.put(uri, imageFile); imageUriForDecoding = imageFile.toURI(); } else { imageUriForDecoding = new URI(uri); } bitmap = decodeImage(imageUriForDecoding); if (bitmap == null) { fireImageLoadingFailedEvent(FailReason.IO_ERROR); } } catch (IOException e) { L.e(e); fireImageLoadingFailedEvent(FailReason.IO_ERROR); if (imageFile.exists()) { imageFile.delete(); } } catch (OutOfMemoryError e) { L.e(e); fireImageLoadingFailedEvent(FailReason.OUT_OF_MEMORY); } catch (Throwable e) { L.e(e); fireImageLoadingFailedEvent(FailReason.UNKNOWN); } return bitmap; }
/** * {@linkplain #stop() Stops ImageLoader} and clears current configuration. <br> * You can {@linkplain #init(ImageLoaderConfiguration) init} ImageLoader with new configuration * after calling this method. */ public void destroy() { if (configuration != null) L.d(LOG_DESTROY); stop(); configuration.diskCache.close(); engine = null; configuration = null; }
private static File getExternalCacheDir(Context context) { File dataDir = new File(new File(Environment.getExternalStorageDirectory(), "Android"), "data"); File appCacheDir = new File(new File(dataDir, context.getPackageName()), "cache"); if (!appCacheDir.exists()) { if (!appCacheDir.mkdirs()) { L.w("Unable to create external cache directory"); return null; } try { new File(appCacheDir, ".nomedia").createNewFile(); } catch (IOException e) { L.i("Can't create \".nomedia\" file in application external cache directory"); } } return appCacheDir; }
/** * ImageLoader参数配置构造器 把构建者中的数据 对全局变量初始化 * * @param builder 构建信息对象 */ private ImageLoaderConfiguration(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); L.writeDebugLogs(builder.writeLogs); }
private Bitmap decodeWithOOMHandling(URI imageUri) throws IOException { Bitmap result = null; ImageDecoder decoder = new ImageDecoder(imageUri, downloader, options); decoder.setLoggingEnabled(loggingEnabled); for (int attempt = 1; attempt <= ATTEMPT_COUNT_TO_DECODE_BITMAP; attempt++) { try { ViewScaleType viewScaleType = ViewScaleType.fromImageView(imageView); result = decoder.decode(targetSize, options.getImageScaleType(), viewScaleType); } catch (OutOfMemoryError e) { L.e(e); switch (attempt) { case 1: System.gc(); break; case 2: configuration.memoryCache.clear(); System.gc(); break; case 3: throw e; } // Wait some time while GC is working SystemClock.sleep(attempt * 1000); continue; } break; } return result; }
/** * @param cacheDir Directory for file caching. <b>Important:</b> Specify separate folder for * cached files. It's needed for right cache limit work. * @param fileNameGenerator Name generator for cached files * @param maxCacheSize Maximum cache directory size (in bytes). If cache size exceeds this limit * then file with the most oldest last usage date will be deleted. */ public TotalSizeLimitedDiscCache( File cacheDir, FileNameGenerator fileNameGenerator, int maxCacheSize) { super(cacheDir, fileNameGenerator, maxCacheSize); if (maxCacheSize < MIN_NORMAL_CACHE_SIZE) { L.w("You set too small disc cache size (less than %1$d Mb)", MIN_NORMAL_CACHE_SIZE_IN_MB); } }
private Bitmap tryLoadBitmap() throws TaskCancelledException { File imageFile = getImageFileInDiscCache(); Bitmap bitmap = null; try { String cacheFileUri = Scheme.FILE.wrap(imageFile.getAbsolutePath()); if (imageFile.exists()) { log(LOG_LOAD_IMAGE_FROM_DISC_CACHE); loadedFrom = LoadedFrom.DISC_CACHE; checkTaskNotActual(); bitmap = decodeImage(cacheFileUri); } if (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) { log(LOG_LOAD_IMAGE_FROM_NETWORK); loadedFrom = LoadedFrom.NETWORK; String imageUriForDecoding = options.isCacheOnDisc() && tryCacheImageOnDisc(imageFile) ? cacheFileUri : uri; checkTaskNotActual(); bitmap = decodeImage(imageUriForDecoding); if (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) { fireFailEvent(FailType.DECODING_ERROR, null); } } } catch (IllegalStateException e) { fireFailEvent(FailType.NETWORK_DENIED, null); } catch (TaskCancelledException e) { throw e; } catch (IOException e) { L.e(e); fireFailEvent(FailType.IO_ERROR, e); if (imageFile.exists()) { imageFile.delete(); } } catch (OutOfMemoryError e) { L.e(e); fireFailEvent(FailType.OUT_OF_MEMORY, e); } catch (Throwable e) { L.e(e); fireFailEvent(FailType.UNKNOWN, e); } return bitmap; }
/** * 设置图片显示线程池线程数量 Sets thread pool size for image display tasks.<br> * Default value - {@link #DEFAULT_THREAD_POOL_SIZE this} */ public Builder threadPoolSize(int threadPoolSize) { if (taskExecutor != null || taskExecutorForCachedImages != null) { L.w(WARNING_OVERLAP_EXECUTOR); } this.threadPoolSize = threadPoolSize; return this; }
/** * Sets maximum memory cache size for {@link android.graphics.Bitmap bitmaps} (in bytes).<br> * Default value - {@link #DEFAULT_MEMORY_CACHE_SIZE this}<br> * <b>NOTE:</b> If you use this method then {@link * com.nostra13.universalimageloader.cache.memory.impl.UsingFreqLimitedMemoryCache * UsingFreqLimitedCache} will be used as memory cache. You can use {@link * #memoryCache(MemoryCacheAware)} method for introduction your own implementation of {@link * MemoryCacheAware}. */ public Builder memoryCacheSize(int memoryCacheSize) { if (memoryCacheSize <= 0) throw new IllegalArgumentException("memoryCacheSize must be a positive number"); if (memoryCache != null) L.w(WARNING_MEMORY_CACHE_ALREADY_SET); this.memoryCacheSize = memoryCacheSize; return this; }
/** * 设置图片内存缓存器 Sets memory cache for {@link android.graphics.Bitmap bitmaps}.<br> * Default value - {@link com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache * LruMemoryCache} 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)} * </ul> */ public Builder memoryCache(MemoryCache memoryCache) { if (memoryCacheSize != 0) { L.w(WARNING_OVERLAP_MEMORY_CACHE); } this.memoryCache = memoryCache; return this; }
/** * Initializes ImageLoader instance with configuration.<br> * If configurations was set before ( {@link #isInited()} == true) then this method does nothing. * <br> * To force initialization with new configuration you should {@linkplain #destroy() destroy * ImageLoader} at first. * * @param configuration {@linkplain ImageLoaderConfiguration ImageLoader configuration} * @throws IllegalArgumentException if <b>configuration</b> parameter is null */ public synchronized void init(ImageLoaderConfiguration configuration) { if (configuration == null) { throw new IllegalArgumentException(ERROR_INIT_CONFIG_WITH_NULL); } if (this.configuration == null) { if (configuration.writeLogs) { L.d(LOG_INIT_CONFIG); } engine = new ImageLoaderEngine(configuration); this.configuration = configuration; } else { L.w(WARNING_RE_INIT_CONFIG); } }
/** * 设置本地文件缓存器中 缓存文件名生成器 Sets name generator for files cached in disk cache.<br> * Default value - {@link * com.nostra13.universalimageloader.core.DefaultConfigurationFactory#createFileNameGenerator() * DefaultConfigurationFactory.createFileNameGenerator()} */ public Builder diskCacheFileNameGenerator(FileNameGenerator fileNameGenerator) { if (diskCache != null) { L.w(WARNING_OVERLAP_DISK_CACHE_NAME_GENERATOR); } this.diskCacheFileNameGenerator = fileNameGenerator; return this; }
/** * 设置加载和显示图片任务的队列任务处理算法类型 Sets type of queue processing for tasks for loading and displaying * images.<br> * Default value - {@link QueueProcessingType#FIFO} */ public Builder tasksProcessingOrder(QueueProcessingType tasksProcessingType) { if (taskExecutor != null || taskExecutorForCachedImages != null) { L.w(WARNING_OVERLAP_EXECUTOR); } this.tasksProcessingType = tasksProcessingType; return this; }
/** * {@linkplain #stop() Stops ImageLoader} and clears current configuration. <br> * You can {@linkplain #init(ImageLoaderConfiguration) init} ImageLoader with new configuration * after calling this method. */ public void destroy() { if (configuration != null && configuration.writeLogs) { L.d(LOG_DESTROY); } stop(); engine = null; configuration = null; }
public tasksProcessingType threadPoolSize(int i) { if (taskExecutor != null || taskExecutorForCachedImages != null) { L.w("threadPoolSize(), threadPriority() and tasksProcessingOrder() calls can overlap taskExecutor() and taskExecutorForCachedImages() calls.", new Object[0]); } threadPoolSize = i; return this; }
public taskExecutor taskExecutorForCachedImages(Executor executor) { if (threadPoolSize != 3 || threadPriority != 4 || tasksProcessingType != DEFAULT_TASK_PROCESSING_TYPE) { L.w("threadPoolSize(), threadPriority() and tasksProcessingOrder() calls can overlap taskExecutor() and taskExecutorForCachedImages() calls.", new Object[0]); } taskExecutorForCachedImages = executor; return this; }
public downloader memoryCache(MemoryCache memorycache) { if (memoryCacheSize != 0) { L.w("memoryCache() and memoryCacheSize() calls overlap each other", new Object[0]); } memoryCache = memorycache; return this; }
public diskCacheFileCount diskCacheFileNameGenerator(FileNameGenerator filenamegenerator) { if (diskCache != null) { L.w("diskCache() and diskCacheFileNameGenerator() calls overlap each other", new Object[0]); } diskCacheFileNameGenerator = filenamegenerator; return this; }
@Override public boolean remove(String imageUri) { try { return cache.remove(getKey(imageUri)); } catch (IOException e) { L.e(e); return false; } }
@Override public void close() { try { cache.close(); } catch (IOException e) { L.e(e); } cache = null; }
@Override public File get(String imageUri) { try { DiskLruCache.Snapshot snapshot = cache.get(getKey(imageUri)); return snapshot == null ? null : snapshot.getFile(0); } catch (IOException e) { L.e(e); return null; } }
@Override public void clear() { try { cache.delete(); } catch (IOException e) { L.e(e); } finally { initCache(cache.getDirectory(), reserveCacheDir, cache.getMaxSize(), cache.getMaxFileCount()); } }
/** * 设置图片缓存自定义执行者 Sets custom {@linkplain Executor executor} for tasks of displaying <b>cached on * disk</b> images (these tasks are executed quickly so UIL prefer to use separate executor for * them).<br> * <br> * If you set the same executor for {@linkplain #taskExecutor(Executor) general tasks} and tasks * about cached images (this method) then these tasks will be in the same thread pool. So * short-lived tasks can wait a long time for their turn.<br> * <br> * <b>NOTE:</b> If you set custom executor then following configuration options will not be * considered for this executor: * * <ul> * <li>{@link #threadPoolSize(int)} * <li>{@link #threadPriority(int)} * <li>{@link #tasksProcessingOrder(QueueProcessingType)} * </ul> * * @see #taskExecutor(Executor) */ public Builder taskExecutorForCachedImages(Executor executorForCachedImages) { if (threadPoolSize != DEFAULT_THREAD_POOL_SIZE || threadPriority != DEFAULT_THREAD_PRIORITY || tasksProcessingType != DEFAULT_TASK_PROCESSING_TYPE) { L.w(WARNING_OVERLAP_EXECUTOR); } this.taskExecutorForCachedImages = executorForCachedImages; return this; }
/** * 设置本地文件缓存器中可缓存的文件大小 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 {@link * com.nostra13.universalimageloader.cache.disc.impl.ext.LruDiskCache LruDiskCache} 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) throw new IllegalArgumentException("maxFileCount must be a positive number"); if (diskCache != null) { L.w(WARNING_OVERLAP_DISK_CACHE_PARAMS); } this.diskCacheFileCount = maxFileCount; return this; }