diff --git a/UniversalImageLoader/src/com/nostra13/universalimageloader/core/ImageLoader.java b/UniversalImageLoader/src/com/nostra13/universalimageloader/core/ImageLoader.java index 2cff72dbf..561e546f2 100644 --- a/UniversalImageLoader/src/com/nostra13/universalimageloader/core/ImageLoader.java +++ b/UniversalImageLoader/src/com/nostra13/universalimageloader/core/ImageLoader.java @@ -6,6 +6,7 @@ import java.util.WeakHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.locks.ReentrantLock; import android.content.res.Configuration; import android.graphics.Bitmap; @@ -42,6 +43,7 @@ public class ImageLoader { private ImageLoadingListener emptyListener; private Map cacheKeyForImageView = Collections.synchronizedMap(new WeakHashMap()); + private Map uriLocks = Collections.synchronizedMap(new WeakHashMap()); private volatile static ImageLoader instance; @@ -209,7 +211,7 @@ public void displayImage(String uri, ImageView imageView, DisplayImageOptions op } checkExecutors(); - ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageView, targetSize, options, listener); + ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageView, targetSize, options, listener, getLockForUri(uri)); LoadAndDisplayImageTask displayImageTask = new LoadAndDisplayImageTask(configuration, imageLoadingInfo, new Handler()); boolean isImageCachedOnDisc = configuration.discCache.get(uri).exists(); if (isImageCachedOnDisc) { @@ -327,4 +329,15 @@ private int getFieldValue(Object object, String fieldName) { } return value; } + + private ReentrantLock getLockForUri(String uri) { + synchronized (uriLocks) { + ReentrantLock lock = uriLocks.get(uri); + if (lock == null) { + lock = new ReentrantLock(); + uriLocks.put(uri, lock); + } + return lock; + } + } } diff --git a/UniversalImageLoader/src/com/nostra13/universalimageloader/core/ImageLoadingInfo.java b/UniversalImageLoader/src/com/nostra13/universalimageloader/core/ImageLoadingInfo.java index 1808d6e7e..54557a36d 100644 --- a/UniversalImageLoader/src/com/nostra13/universalimageloader/core/ImageLoadingInfo.java +++ b/UniversalImageLoader/src/com/nostra13/universalimageloader/core/ImageLoadingInfo.java @@ -1,5 +1,7 @@ package com.nostra13.universalimageloader.core; +import java.util.concurrent.locks.ReentrantLock; + import android.net.Uri; import android.widget.ImageView; @@ -23,13 +25,15 @@ final class ImageLoadingInfo { final ImageSize targetSize; final DisplayImageOptions options; final ImageLoadingListener listener; + final ReentrantLock loadFromUriLock; - public ImageLoadingInfo(String uri, ImageView imageView, ImageSize targetSize, DisplayImageOptions options, ImageLoadingListener listener) { + public ImageLoadingInfo(String uri, ImageView imageView, ImageSize targetSize, DisplayImageOptions options, ImageLoadingListener listener, ReentrantLock loadFromUriLock) { this.uri = Uri.encode(uri, "@#&=*+-_.,:!?()/~'%"); this.imageView = imageView; this.targetSize = targetSize; this.options = options; this.listener = listener; + this.loadFromUriLock = loadFromUriLock; memoryCacheKey = MemoryCacheKeyUtil.generateKey(uri, targetSize); } } diff --git a/UniversalImageLoader/src/com/nostra13/universalimageloader/core/LoadAndDisplayImageTask.java b/UniversalImageLoader/src/com/nostra13/universalimageloader/core/LoadAndDisplayImageTask.java index 6ac743c80..dd27478b0 100644 --- a/UniversalImageLoader/src/com/nostra13/universalimageloader/core/LoadAndDisplayImageTask.java +++ b/UniversalImageLoader/src/com/nostra13/universalimageloader/core/LoadAndDisplayImageTask.java @@ -32,6 +32,8 @@ final class LoadAndDisplayImageTask implements Runnable { private static final String LOG_START_DISPLAY_IMAGE_TASK = "Start display image task [%s]"; + private static final String LOG_WAITING = "Image already is loading. Waiting... [%s]"; + private static final String LOG_GET_IMAGE_FROM_MEMORY_CACHE_AFTER_WAITING = "...Get cached bitmap from memory after waiting. [%s]"; private static final String LOG_LOAD_IMAGE_FROM_INTERNET = "Load image from Internet [%s]"; private static final String LOG_LOAD_IMAGE_FROM_DISC_CACHE = "Load image from disc cache [%s]"; private static final String LOG_CACHE_IMAGE_IN_MEMORY = "Cache image in memory [%s]"; @@ -52,17 +54,35 @@ public LoadAndDisplayImageTask(ImageLoaderConfiguration configuration, ImageLoad @Override public void run() { - if (configuration.loggingEnabled) Log.i(ImageLoader.TAG, String.format(LOG_START_DISPLAY_IMAGE_TASK, imageLoadingInfo.memoryCacheKey)); + if (configuration.loggingEnabled) { + Log.i(ImageLoader.TAG, String.format(LOG_START_DISPLAY_IMAGE_TASK, imageLoadingInfo.memoryCacheKey)); + if (imageLoadingInfo.loadFromUriLock.isLocked()) { + Log.i(ImageLoader.TAG, String.format(LOG_WAITING, imageLoadingInfo.memoryCacheKey)); + } + } - if (checkTaskIsNotActual()) return; - Bitmap bmp = tryLoadBitmap(); - if (bmp == null) return; + imageLoadingInfo.loadFromUriLock.lock(); + Bitmap bmp; + try { + if (checkTaskIsNotActual()) return; - if (checkTaskIsNotActual()) return; - if (imageLoadingInfo.options.isCacheInMemory()) { - if (configuration.loggingEnabled) Log.i(ImageLoader.TAG, String.format(LOG_CACHE_IMAGE_IN_MEMORY, imageLoadingInfo.memoryCacheKey)); + bmp = ImageLoader.getInstance().getMemoryCache().get(imageLoadingInfo.memoryCacheKey); + if (bmp == null) { + bmp = tryLoadBitmap(); + if (bmp == null) return; - configuration.memoryCache.put(imageLoadingInfo.memoryCacheKey, bmp); + if (checkTaskIsNotActual()) return; + if (imageLoadingInfo.options.isCacheInMemory()) { + if (configuration.loggingEnabled) Log.i(ImageLoader.TAG, String.format(LOG_CACHE_IMAGE_IN_MEMORY, imageLoadingInfo.memoryCacheKey)); + + configuration.memoryCache.put(imageLoadingInfo.memoryCacheKey, bmp); + } + } else { + if (configuration.loggingEnabled) + Log.i(ImageLoader.TAG, String.format(LOG_GET_IMAGE_FROM_MEMORY_CACHE_AFTER_WAITING, imageLoadingInfo.memoryCacheKey)); + } + } finally { + imageLoadingInfo.loadFromUriLock.unlock(); } if (checkTaskIsNotActual()) return;