ImageLoader加载图片前要初始化,初始化时需要一个 ImageLoaderConfiguration
初始化代码:
ImageLoader.getInstance().init(configuration);
1. ImageLoaderConfiguration configuration1= ImageLoaderConfiguration.createDefault(context);
2. ImageLoaderConfiguration configuration2=new ImageLoaderConfiguration.Builder(context).build();
public static ImageLoaderConfiguration createDefault(Context context) { return new Builder(context).build(); }
再来看一下Builder相关代码:
Builder构造函数:
public Builder(Context context) { this.context = context.getApplicationContext(); }
Builder中builder()方法相关代码:
/** Builds configured {@link ImageLoaderConfiguration} object */ public ImageLoaderConfiguration build() { initEmptyFieldsWithDefaultValues(); return new ImageLoaderConfiguration(this); } 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(); } }
if (memoryCache == null) { memoryCache = DefaultConfigurationFactory.createMemoryCache(context, memoryCacheSize); }
package com.nostra13.universalimageloader.cache.memory.impl; import android.graphics.Bitmap; import com.nostra13.universalimageloader.cache.memory.MemoryCache; import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; /** * A cache that holds strong references to a limited number of Bitmaps. Each time a Bitmap is accessed, it is moved to * the head of a queue. When a Bitmap is added to a full cache, the Bitmap at the end of that queue is evicted and may * become eligible for garbage collection.<br /> * <br /> * <b>NOTE:</b> This cache uses only strong references for stored Bitmaps. * * @author Sergey Tarasevich (nostra13[at]gmail[dot]com) * @since 1.8.1 */ public class LruMemoryCache implements MemoryCache { private final LinkedHashMap<String, Bitmap> map; private final int maxSize; /** Size of this cache in bytes */ private int size; /** @param maxSize Maximum sum of the sizes of the Bitmaps in this cache */ public LruMemoryCache(int maxSize) { if (maxSize <= 0) { throw new IllegalArgumentException("maxSize <= 0"); } this.maxSize = maxSize; this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true); } /** * Returns the Bitmap for {@code key} if it exists in the cache. If a Bitmap was returned, it is moved to the head * of the queue. This returns null if a Bitmap is not cached. */ @Override public final Bitmap get(String key) { if (key == null) { throw new NullPointerException("key == null"); } synchronized (this) { return map.get(key); } } /** Caches {@code Bitmap} for {@code key}. The Bitmap is moved to the head of the queue. */ @Override public final boolean put(String key, Bitmap value) { if (key == null || value == null) { throw new NullPointerException("key == null || value == null"); } synchronized (this) { size += sizeOf(key, value); Bitmap previous = map.put(key, value); if (previous != null) { size -= sizeOf(key, previous); } } trimToSize(maxSize); return true; } /** * Remove the eldest entries until the total of remaining entries is at or below the requested size. * * @param maxSize the maximum size of the cache before returning. May be -1 to evict even 0-sized elements. */ private void trimToSize(int maxSize) { while (true) { String key; Bitmap value; synchronized (this) { if (size < 0 || (map.isEmpty() && size != 0)) { throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!"); } if (size <= maxSize || map.isEmpty()) { break; } Map.Entry<String, Bitmap> toEvict = map.entrySet().iterator().next(); if (toEvict == null) { break; } key = toEvict.getKey(); value = toEvict.getValue(); map.remove(key); size -= sizeOf(key, value); } } } /** Removes the entry for {@code key} if it exists. */ @Override public final Bitmap remove(String key) { if (key == null) { throw new NullPointerException("key == null"); } synchronized (this) { Bitmap previous = map.remove(key); if (previous != null) { size -= sizeOf(key, previous); } return previous; } } @Override public Collection<String> keys() { synchronized (this) { return new HashSet<String>(map.keySet()); } } @Override public void clear() { trimToSize(-1); // -1 will evict 0-sized elements } /** * Returns the size {@code Bitmap} in bytes. * <p/> * An entry's size must not change while it is in the cache. */ private int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight(); } @Override public synchronized final String toString() { return String.format("LruCache[maxSize=%d]", maxSize); } }
我们发现使用的是java.util.LinkedHashMap<String, Bitmap>来存储Bitmap,并且是强引用,并没用采用软引用或弱引用。
再看这句话:
if (diskCache == null) { if (diskCacheFileNameGenerator == null) { //文件名生成器,源码中使用的是url的哈希值 diskCacheFileNameGenerator = DefaultConfigurationFactory.createFileNameGenerator(); } diskCache = DefaultConfigurationFactory.createDiskCache(context, diskCacheFileNameGenerator, diskCacheSize, diskCacheFileCount); }
我们在builder中还看到这样一句代码:
if (downloader == null) { downloader = DefaultConfigurationFactory.createImageDownloader(context); }
protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException { HttpURLConnection conn = createConnection(imageUri, extra); int redirectCount = 0; //请求重定向 while (conn.getResponseCode() / 100 == 3 && redirectCount < MAX_REDIRECT_COUNT) { conn = createConnection(conn.getHeaderField("Location"), extra); redirectCount++; } InputStream imageStream; try { imageStream = conn.getInputStream(); } catch (IOException e) { // Read all data to allow reuse connection (http://bit.ly/1ad35PY) IoUtils.readAndCloseStream(conn.getErrorStream()); throw e; } if (!shouldBeProcessed(conn)) { IoUtils.closeSilently(imageStream); throw new IOException("Image request failed with response code " + conn.getResponseCode()); } return new ContentLengthInputStream(new BufferedInputStream(imageStream, BUFFER_SIZE), conn.getContentLength()); }所以ImageLoader默认使用的网络请求是 HttpURLConnection,所以我们可以很方便的修改为自定义的网络请求,如使用okhttp等。
ImageLoader中默认采用BaseImageDecoder,可以矫正图像(旋转等)。
所以如果我们不想使用默认 的配置初始化,我们可以这样初始化:
ImageLoaderConfiguration.Builder builder=new ImageLoaderConfiguration.Builder(context); builder.imageDownloader(new ImageDownloader() { /** * @param imageUri 图片url * * @param extra 可以忽略不使用 */ @Override public InputStream getStream(String imageUri, Object extra) throws IOException { //使用第三方网络请求类库下载图片 return null; } }); //采用软引用 builder.memoryCache(new BaseMemoryCache() { @Override protected Reference<Bitmap> createReference(Bitmap value) { return new SoftReference<Bitmap>(value); } }); builder.threadPoolSize(5); //省去部分自定义。。。。 ImageLoader.getInstance().init(builder.build());