
com.nostra13.universalimageloader.core.ImageLoader Maven / Gradle / Ivy
/*******************************************************************************
* Copyright 2011-2013 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 com.nostra13.universalimageloader.core;
import java.lang.reflect.Field;
import android.graphics.Bitmap;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import com.nostra13.universalimageloader.cache.disc.DiscCacheAware;
import com.nostra13.universalimageloader.cache.memory.MemoryCacheAware;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.assist.FlushedInputStream;
import com.nostra13.universalimageloader.core.assist.ImageLoadingListener;
import com.nostra13.universalimageloader.core.assist.ImageSize;
import com.nostra13.universalimageloader.core.assist.MemoryCacheUtil;
import com.nostra13.universalimageloader.core.assist.SimpleImageLoadingListener;
import com.nostra13.universalimageloader.core.display.BitmapDisplayer;
import com.nostra13.universalimageloader.core.display.FakeBitmapDisplayer;
import com.nostra13.universalimageloader.utils.L;
/**
* Singletone for image loading and displaying at {@link ImageView ImageViews}
* NOTE: {@link #init(ImageLoaderConfiguration)} method must be called before any other method.
*
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
* @since 1.0.0
*/
public class ImageLoader {
public static final String TAG = ImageLoader.class.getSimpleName();
static final String LOG_WAITING_FOR_RESUME = "ImageLoader is paused. Waiting... [%s]";
static final String LOG_RESUME_AFTER_PAUSE = ".. Resume loading [%s]";
static final String LOG_DELAY_BEFORE_LOADING = "Delay %d ms before loading... [%s]";
static final String LOG_START_DISPLAY_IMAGE_TASK = "Start display image task [%s]";
static final String LOG_WAITING_FOR_IMAGE_LOADED = "Image already is loading. Waiting... [%s]";
static final String LOG_GET_IMAGE_FROM_MEMORY_CACHE_AFTER_WAITING = "...Get cached bitmap from memory after waiting. [%s]";
static final String LOG_LOAD_IMAGE_FROM_MEMORY_CACHE = "Load image from memory cache [%s]";
static final String LOG_LOAD_IMAGE_FROM_INTERNET = "Load image from Internet [%s]";
static final String LOG_LOAD_IMAGE_FROM_DISC_CACHE = "Load image from disc cache [%s]";
static final String LOG_IMAGE_SUBSAMPLING = "Original image (%1$dx%2$d) is going to be subsampled to %3$dx%4$d view. Computed scale size - %5$d";
static final String LOG_IMAGE_SCALED = "Subsampled image (%1$dx%2$d) was scaled to %3$dx%4$d";
static final String LOG_PREPROCESS_IMAGE = "PreProcess image before caching in memory [%s]";
static final String LOG_POSTPROCESS_IMAGE = "PostProcess image before displaying [%s]";
static final String LOG_CACHE_IMAGE_IN_MEMORY = "Cache image in memory [%s]";
static final String LOG_CACHE_IMAGE_ON_DISC = "Cache image on disc [%s]";
static final String LOG_DISPLAY_IMAGE_IN_IMAGEVIEW = "Display image in ImageView [%s]";
static final String LOG_TASK_CANCELLED = "ImageView is reused for another image. Task is cancelled. [%s]";
static final String LOG_TASK_INTERRUPTED = "Task was interrupted [%s]";
static final String LOG_CANT_DECODE_IMAGE = "Image can't be decoded [%s]";
private static final String ERROR_WRONG_ARGUMENTS = "Wrong arguments were passed to displayImage() method (ImageView reference must not be null)";
private static final String ERROR_NOT_INIT = "ImageLoader must be init with configuration before using";
private static final String ERROR_INIT_CONFIG_WITH_NULL = "ImageLoader configuration can not be initialized with null";
private ImageLoaderConfiguration configuration;
private ImageLoaderEngine engine;
private final ImageLoadingListener emptyListener = new SimpleImageLoadingListener();
private final BitmapDisplayer fakeBitmapDisplayer = new FakeBitmapDisplayer();
private volatile static ImageLoader instance;
/** Returns singleton class instance */
public static ImageLoader getInstance() {
if (instance == null) {
synchronized (ImageLoader.class) {
if (instance == null) {
instance = new ImageLoader();
}
}
}
return instance;
}
protected ImageLoader() {
}
/**
* Initializes ImageLoader's singleton instance with configuration. Method should be called once (each
* following call will have no effect)
*
* @param configuration {@linkplain ImageLoaderConfiguration ImageLoader configuration}
* @throws IllegalArgumentException if configuration parameter is null
*/
public synchronized void init(ImageLoaderConfiguration configuration) {
if (configuration == null) {
throw new IllegalArgumentException(ERROR_INIT_CONFIG_WITH_NULL);
}
if (this.configuration == null) {
engine = new ImageLoaderEngine(configuration);
this.configuration = configuration;
}
}
/**
* Returns true - if ImageLoader {@linkplain #init(ImageLoaderConfiguration) is initialized with
* configuration}; false - otherwise
*/
public boolean isInited() {
return configuration != null;
}
/**
* Adds display image task to execution pool. Image will be set to ImageView when it's turn.
* Default {@linkplain DisplayImageOptions display image options} from {@linkplain ImageLoaderConfiguration
* configuration} will be used.
* NOTE: {@link #init(ImageLoaderConfiguration)} method must be called before this method call
*
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
* @param imageView {@link ImageView} which should display image
*
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
* @throws IllegalArgumentException if passed imageView is null
*/
public void displayImage(String uri, ImageView imageView) {
displayImage(uri, imageView, null, null);
}
/**
* Adds display image task to execution pool. Image will be set to ImageView when it's turn.
* NOTE: {@link #init(ImageLoaderConfiguration)} method must be called before this method call
*
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
* @param imageView {@link ImageView} which should display image
* @param options {@linkplain DisplayImageOptions Display image options} for image displaying. If null -
* default display image options
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
* configuration} will be used.
*
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
* @throws IllegalArgumentException if passed imageView is null
*/
public void displayImage(String uri, ImageView imageView, DisplayImageOptions options) {
displayImage(uri, imageView, options, null);
}
/**
* Adds display image task to execution pool. Image will be set to ImageView when it's turn.
* Default {@linkplain DisplayImageOptions display image options} from {@linkplain ImageLoaderConfiguration
* configuration} will be used.
* NOTE: {@link #init(ImageLoaderConfiguration)} method must be called before this method call
*
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
* @param imageView {@link ImageView} which should display image
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on UI
* thread.
*
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
* @throws IllegalArgumentException if passed imageView is null
*/
public void displayImage(String uri, ImageView imageView, ImageLoadingListener listener) {
displayImage(uri, imageView, null, listener);
}
/**
* Adds display image task to execution pool. Image will be set to ImageView when it's turn.
* NOTE: {@link #init(ImageLoaderConfiguration)} method must be called before this method call
*
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
* @param imageView {@link ImageView} which should display image
* @param options {@linkplain DisplayImageOptions Display image options} for image displaying. If null -
* default display image options
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
* configuration} will be used.
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on UI
* thread.
*
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
* @throws IllegalArgumentException if passed imageView is null
*/
public void displayImage(String uri, ImageView imageView, DisplayImageOptions options, ImageLoadingListener listener) {
checkConfiguration();
if (imageView == null) {
throw new IllegalArgumentException(ERROR_WRONG_ARGUMENTS);
}
if (listener == null) {
listener = emptyListener;
}
if (options == null) {
options = configuration.defaultDisplayImageOptions;
}
if (uri == null || uri.length() == 0) {
engine.cancelDisplayTaskFor(imageView);
listener.onLoadingStarted(uri, imageView);
if (options.shouldShowImageForEmptyUri()) {
imageView.setImageResource(options.getImageForEmptyUri());
} else {
imageView.setImageBitmap(null);
}
listener.onLoadingComplete(uri, imageView, null);
return;
}
ImageSize targetSize = getImageSizeScaleTo(imageView);
String memoryCacheKey = MemoryCacheUtil.generateKey(uri, targetSize);
engine.prepareDisplayTaskFor(imageView, memoryCacheKey);
listener.onLoadingStarted(uri, imageView);
Bitmap bmp = configuration.memoryCache.get(memoryCacheKey);
if (bmp != null && !bmp.isRecycled()) {
if (configuration.loggingEnabled) L.i(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey);
if (options.shouldPostProcess()) {
ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageView, targetSize, options, listener, engine.getLockForUri(uri));
ProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo, new Handler());
engine.submit(displayTask);
} else {
options.getDisplayer().display(bmp, imageView);
listener.onLoadingComplete(uri, imageView, bmp);
}
} else {
if (options.shouldShowStubImage()) {
imageView.setImageResource(options.getStubImage());
} else {
if (options.isResetViewBeforeLoading()) {
imageView.setImageBitmap(null);
}
}
ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageView, targetSize, options, listener, engine.getLockForUri(uri));
LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo, new Handler());
engine.submit(displayTask);
}
}
/**
* Adds load image task to execution pool. Image will be returned with
* {@link ImageLoadingListener#onLoadingComplete(Bitmap) callback}.
* NOTE: {@link #init(ImageLoaderConfiguration)} method must be called before this method call
*
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on UI
* thread.
*
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
*/
public void loadImage(String uri, ImageLoadingListener listener) {
loadImage(uri, null, null, listener);
}
/**
* Adds load image task to execution pool. Image will be returned with
* {@link ImageLoadingListener#onLoadingComplete(Bitmap) callback}.
* NOTE: {@link #init(ImageLoaderConfiguration)} method must be called before this method call
*
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
* @param minImageSize Minimal size for {@link Bitmap} which will be returned in
* {@linkplain ImageLoadingListener#onLoadingComplete(Bitmap) callback}. Downloaded image will be decoded
* and scaled to {@link Bitmap} of the size which is equal or larger (usually a bit larger) than
* incoming minImageSize .
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on UI
* thread.
*
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
*/
public void loadImage(String uri, ImageSize minImageSize, ImageLoadingListener listener) {
loadImage(uri, minImageSize, null, listener);
}
/**
* Adds load image task to execution pool. Image will be returned with
* {@link ImageLoadingListener#onLoadingComplete(Bitmap) callback}.
* NOTE: {@link #init(ImageLoaderConfiguration)} method must be called before this method call
*
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
* @param options {@linkplain DisplayImageOptions Display image options} for image displaying. If null -
* default display image options
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
* configuration} will be used.
* Incoming options should contain {@link FakeBitmapDisplayer} as displayer.
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on UI
* thread.
*
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
*/
public void loadImage(String uri, DisplayImageOptions options, ImageLoadingListener listener) {
loadImage(uri, null, options, listener);
}
/**
* Adds load image task to execution pool. Image will be returned with
* {@link ImageLoadingListener#onLoadingComplete(Bitmap) callback}.
* NOTE: {@link #init(ImageLoaderConfiguration)} method must be called before this method call
*
* @param uri Image URI (i.e. "http://site.com/image.png", "file:///mnt/sdcard/image.png")
* @param targetImageSize Minimal size for {@link Bitmap} which will be returned in
* {@linkplain ImageLoadingListener#onLoadingComplete(Bitmap) callback}. Downloaded image will be decoded
* and scaled to {@link Bitmap} of the size which is equal or larger (usually a bit larger) than
* incoming minImageSize .
* @param options {@linkplain DisplayImageOptions Display image options} for image displaying. If null -
* default display image options
* {@linkplain ImageLoaderConfiguration.Builder#defaultDisplayImageOptions(DisplayImageOptions) from
* configuration} will be used.
* Incoming options should contain {@link FakeBitmapDisplayer} as displayer.
* @param listener {@linkplain ImageLoadingListener Listener} for image loading process. Listener fires events on UI
* thread.
*
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
*/
public void loadImage(String uri, ImageSize targetImageSize, DisplayImageOptions options, ImageLoadingListener listener) {
checkConfiguration();
if (targetImageSize == null) {
targetImageSize = new ImageSize(configuration.maxImageWidthForMemoryCache, configuration.maxImageHeightForMemoryCache);
}
if (options == null) {
options = configuration.defaultDisplayImageOptions;
}
DisplayImageOptions optionsWithFakeDisplayer;
if (options.getDisplayer() instanceof FakeBitmapDisplayer) {
optionsWithFakeDisplayer = options;
} else {
optionsWithFakeDisplayer = new DisplayImageOptions.Builder().cloneFrom(options).displayer(fakeBitmapDisplayer).build();
}
ImageView fakeImage = new ImageView(configuration.context);
fakeImage.setLayoutParams(new LayoutParams(targetImageSize.getWidth(), targetImageSize.getHeight()));
fakeImage.setScaleType(ScaleType.CENTER_CROP);
displayImage(uri, fakeImage, optionsWithFakeDisplayer, listener);
}
/**
* Checks if ImageLoader's configuration was initialized
*
* @throws IllegalStateException if configuration wasn't initialized
*/
private void checkConfiguration() {
if (configuration == null) {
throw new IllegalStateException(ERROR_NOT_INIT);
}
}
/**
* Returns memory cache
*
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
*/
public MemoryCacheAware getMemoryCache() {
checkConfiguration();
return configuration.memoryCache;
}
/**
* Clears memory cache
*
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
*/
public void clearMemoryCache() {
checkConfiguration();
configuration.memoryCache.clear();
}
/**
* Returns disc cache
*
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
*/
public DiscCacheAware getDiscCache() {
checkConfiguration();
return configuration.discCache;
}
/**
* Clears disc cache.
*
* @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
*/
public void clearDiscCache() {
checkConfiguration();
configuration.discCache.clear();
}
/** Returns URI of image which is loading at this moment into passed {@link ImageView} */
public String getLoadingUriForView(ImageView imageView) {
return engine.getLoadingUriForView(imageView);
}
/**
* Cancel the task of loading and displaying image for passed {@link ImageView}.
*
* @param imageView {@link ImageView} for which display task will be cancelled
*/
public void cancelDisplayTask(ImageView imageView) {
engine.cancelDisplayTaskFor(imageView);
}
/**
* Denies or allows ImageLoader to download images from the network.
*
* If downloads are denied and if image isn't cached then
* {@link ImageLoadingListener#onLoadingFailed(String, View, FailReason)} callback will be fired with
* {@link FailReason#NETWORK_DENIED}
*
* @param denyNetworkDownloads pass true - to deny engine to download images from the network; false -
* to allow engine to download images from network.
*/
void denyNetworkDownloads(boolean denyNetworkDownloads) {
engine.denyNetworkDownloads(denyNetworkDownloads);
}
/**
* Sets option whether ImageLoader will use {@link FlushedInputStream} for network downloads to handle this known problem or not.
*
* @param handleSlowNetwork pass true - to use {@link FlushedInputStream} for network downloads; false
* - otherwise.
*/
void handleSlowNetwork(boolean handleSlowNetwork) {
engine.handleSlowNetwork(handleSlowNetwork);
}
/**
* Pause ImageLoader. All new "load&display" tasks won't be executed until ImageLoader is {@link #resume() resumed}.
* Already running tasks are not paused.
*/
public void pause() {
engine.pause();
}
/** Resumes waiting "load&display" tasks */
public void resume() {
engine.resume();
}
/** Stops all running display image tasks, discards all other scheduled tasks */
public void stop() {
engine.stop();
}
/**
* Defines image size for loading at memory (for memory economy) by {@link ImageView} parameters.
* Size computing algorithm:
* 1) Get the actual drawn getWidth() and getHeight() of the View. If view haven't drawn yet then go
* to step #2.
* 2) Get layout_width and layout_height. If both of them haven't exact value then go to step #3.
* 3) Get maxWidth and maxHeight. If both of them are not set then go to step #4.
* 4) Get maxImageWidthForMemoryCache and maxImageHeightForMemoryCache from configuration. If both of
* them are not set then go to step #5.
* 5) Get device screen dimensions.
*/
private ImageSize getImageSizeScaleTo(ImageView imageView) {
final DisplayMetrics displayMetrics = imageView.getContext().getResources().getDisplayMetrics();
final LayoutParams params = imageView.getLayoutParams();
int width = params.width == LayoutParams.WRAP_CONTENT ? 0 : imageView.getWidth(); // Get actual image width
if (width <= 0) width = params.width; // Get layout width parameter
if (width <= 0) width = getFieldValue(imageView, "mMaxWidth"); // Check maxWidth parameter
if (width <= 0) width = configuration.maxImageWidthForMemoryCache;
if (width <= 0) width = displayMetrics.widthPixels;
int height = params.height != LayoutParams.WRAP_CONTENT ? 0 : imageView.getHeight(); // Get actual image height
if (height <= 0) height = params.height; // Get layout height parameter
if (height <= 0) height = getFieldValue(imageView, "mMaxHeight"); // Check maxHeight parameter
if (height <= 0) height = configuration.maxImageHeightForMemoryCache;
if (height <= 0) height = displayMetrics.heightPixels;
return new ImageSize(width, height);
}
private int getFieldValue(Object object, String fieldName) {
int value = 0;
try {
Field field = ImageView.class.getDeclaredField(fieldName);
field.setAccessible(true);
int fieldValue = (Integer) field.get(object);
if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) {
value = fieldValue;
}
} catch (Exception e) {
L.e(e);
}
return value;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy