mirror of
https://github.com/AntennaPod/AntennaPod.git
synced 2025-01-31 19:04:52 +01:00
Prevent images from being loaded multiple times
(copied from AntennaPodSP)
This commit is contained in:
parent
dfa10a5989
commit
b9ab10253a
@ -1,14 +1,8 @@
|
||||
package de.danoeh.antennapod.asynctask;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Handler;
|
||||
import android.support.v4.util.LruCache;
|
||||
import android.util.Log;
|
||||
@ -17,214 +11,228 @@ import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.PodcastApp;
|
||||
import de.danoeh.antennapod.R;
|
||||
|
||||
/** Caches and loads FeedImage bitmaps in the background */
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
/**
|
||||
* Caches and loads FeedImage bitmaps in the background
|
||||
*/
|
||||
public class ImageLoader {
|
||||
private static final String TAG = "ImageLoader";
|
||||
private static ImageLoader singleton;
|
||||
private static final String TAG = "ImageLoader";
|
||||
private static ImageLoader singleton;
|
||||
|
||||
public static final int IMAGE_TYPE_THUMBNAIL = 0;
|
||||
public static final int IMAGE_TYPE_COVER = 1;
|
||||
public static final int IMAGE_TYPE_THUMBNAIL = 0;
|
||||
public static final int IMAGE_TYPE_COVER = 1;
|
||||
|
||||
private Handler handler;
|
||||
private ExecutorService executor;
|
||||
private Handler handler;
|
||||
private ExecutorService executor;
|
||||
|
||||
/**
|
||||
* Stores references to loaded bitmaps. Bitmaps can be accessed by the id of
|
||||
* the FeedImage the bitmap belongs to.
|
||||
*/
|
||||
/**
|
||||
* Stores references to loaded bitmaps. Bitmaps can be accessed by the id of
|
||||
* the FeedImage the bitmap belongs to.
|
||||
*/
|
||||
|
||||
final int memClass = ((ActivityManager) PodcastApp.getInstance()
|
||||
.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
|
||||
final int memClass = ((ActivityManager) PodcastApp.getInstance()
|
||||
.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
|
||||
|
||||
// Use 1/8th of the available memory for this memory cache.
|
||||
final int thumbnailCacheSize = 1024 * 1024 * memClass / 8;
|
||||
// Use 1/8th of the available memory for this memory cache.
|
||||
final int thumbnailCacheSize = 1024 * 1024 * memClass / 8;
|
||||
|
||||
private LruCache<String, CachedBitmap> coverCache;
|
||||
private LruCache<String, CachedBitmap> thumbnailCache;
|
||||
private LruCache<String, CachedBitmap> coverCache;
|
||||
private LruCache<String, CachedBitmap> thumbnailCache;
|
||||
|
||||
private ImageLoader() {
|
||||
handler = new Handler();
|
||||
executor = createExecutor();
|
||||
private ImageLoader() {
|
||||
handler = new Handler();
|
||||
executor = createExecutor();
|
||||
|
||||
coverCache = new LruCache<String, CachedBitmap>(1);
|
||||
coverCache = new LruCache<String, CachedBitmap>(1);
|
||||
|
||||
thumbnailCache = new LruCache<String, CachedBitmap>(thumbnailCacheSize) {
|
||||
thumbnailCache = new LruCache<String, CachedBitmap>(thumbnailCacheSize) {
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
protected int sizeOf(String key, CachedBitmap value) {
|
||||
if (Integer.valueOf(android.os.Build.VERSION.SDK_INT) >= 12)
|
||||
return value.getBitmap().getByteCount();
|
||||
else
|
||||
return (value.getBitmap().getRowBytes() * value.getBitmap()
|
||||
.getHeight());
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
protected int sizeOf(String key, CachedBitmap value) {
|
||||
if (Integer.valueOf(android.os.Build.VERSION.SDK_INT) >= 12)
|
||||
return value.getBitmap().getByteCount();
|
||||
else
|
||||
return (value.getBitmap().getRowBytes() * value.getBitmap()
|
||||
.getHeight());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private ExecutorService createExecutor() {
|
||||
return Executors.newFixedThreadPool(Runtime.getRuntime()
|
||||
.availableProcessors(), new ThreadFactory() {
|
||||
private ExecutorService createExecutor() {
|
||||
return Executors.newFixedThreadPool(Runtime.getRuntime()
|
||||
.availableProcessors(), new ThreadFactory() {
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(r);
|
||||
t.setPriority(Thread.MIN_PRIORITY);
|
||||
return t;
|
||||
}
|
||||
});
|
||||
}
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(r);
|
||||
t.setPriority(Thread.MIN_PRIORITY);
|
||||
return t;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static synchronized ImageLoader getInstance() {
|
||||
if (singleton == null) {
|
||||
singleton = new ImageLoader();
|
||||
}
|
||||
return singleton;
|
||||
}
|
||||
public static synchronized ImageLoader getInstance() {
|
||||
if (singleton == null) {
|
||||
singleton = new ImageLoader();
|
||||
}
|
||||
return singleton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a bitmap from the cover cache. If the bitmap is not in the cache, it
|
||||
* will be loaded from the disk. This method should either be called if the
|
||||
* ImageView's size has already been set or inside a Runnable which is
|
||||
* posted to the ImageView's message queue.
|
||||
*/
|
||||
public void loadCoverBitmap(ImageWorkerTaskResource source, ImageView target) {
|
||||
loadCoverBitmap(source, target, target.getHeight());
|
||||
}
|
||||
/**
|
||||
* Load a bitmap from the cover cache. If the bitmap is not in the cache, it
|
||||
* will be loaded from the disk. This method should either be called if the
|
||||
* ImageView's size has already been set or inside a Runnable which is
|
||||
* posted to the ImageView's message queue.
|
||||
*/
|
||||
public void loadCoverBitmap(ImageWorkerTaskResource source, ImageView target) {
|
||||
loadCoverBitmap(source, target, target.getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a bitmap from the cover cache. If the bitmap is not in the cache, it
|
||||
* will be loaded from the disk. This method should either be called if the
|
||||
* ImageView's size has already been set or inside a Runnable which is
|
||||
* posted to the ImageView's message queue.
|
||||
*/
|
||||
public void loadCoverBitmap(ImageWorkerTaskResource source,
|
||||
ImageView target, int length) {
|
||||
final int defaultCoverResource = getDefaultCoverResource(target
|
||||
.getContext());
|
||||
/**
|
||||
* Load a bitmap from the cover cache. If the bitmap is not in the cache, it
|
||||
* will be loaded from the disk. This method should either be called if the
|
||||
* ImageView's size has already been set or inside a Runnable which is
|
||||
* posted to the ImageView's message queue.
|
||||
*/
|
||||
public void loadCoverBitmap(ImageWorkerTaskResource source,
|
||||
ImageView target, int length) {
|
||||
final int defaultCoverResource = getDefaultCoverResource(target
|
||||
.getContext());
|
||||
final String cacheKey;
|
||||
if (source != null && (cacheKey = source.getImageLoaderCacheKey()) != null) {
|
||||
final Object currentTag = target.getTag(R.id.imageloader_key);
|
||||
if (currentTag == null || !cacheKey.equals(currentTag)) {
|
||||
target.setTag(R.id.imageloader_key, cacheKey);
|
||||
CachedBitmap cBitmap = getBitmapFromCoverCache(cacheKey);
|
||||
if (cBitmap != null && cBitmap.getLength() >= length) {
|
||||
target.setImageBitmap(cBitmap.getBitmap());
|
||||
} else {
|
||||
target.setImageResource(defaultCoverResource);
|
||||
BitmapDecodeWorkerTask worker = new BitmapDecodeWorkerTask(
|
||||
handler, target, source, length, IMAGE_TYPE_COVER);
|
||||
executor.submit(worker);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
target.setImageResource(defaultCoverResource);
|
||||
}
|
||||
}
|
||||
|
||||
if (source != null && source.getImageLoaderCacheKey() != null) {
|
||||
target.setTag(R.id.imageloader_key, source.getImageLoaderCacheKey());
|
||||
CachedBitmap cBitmap = getBitmapFromCoverCache(source.getImageLoaderCacheKey());
|
||||
if (cBitmap != null && cBitmap.getLength() >= length) {
|
||||
target.setImageBitmap(cBitmap.getBitmap());
|
||||
} else {
|
||||
target.setImageResource(defaultCoverResource);
|
||||
BitmapDecodeWorkerTask worker = new BitmapDecodeWorkerTask(
|
||||
handler, target, source, length, IMAGE_TYPE_COVER);
|
||||
executor.submit(worker);
|
||||
}
|
||||
} else {
|
||||
target.setImageResource(defaultCoverResource);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Load a bitmap from the thumbnail cache. If the bitmap is not in the
|
||||
* cache, it will be loaded from the disk. This method should either be
|
||||
* called if the ImageView's size has already been set or inside a Runnable
|
||||
* which is posted to the ImageView's message queue.
|
||||
*/
|
||||
public void loadThumbnailBitmap(ImageWorkerTaskResource source,
|
||||
ImageView target) {
|
||||
loadThumbnailBitmap(source, target, target.getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a bitmap from the thumbnail cache. If the bitmap is not in the
|
||||
* cache, it will be loaded from the disk. This method should either be
|
||||
* called if the ImageView's size has already been set or inside a Runnable
|
||||
* which is posted to the ImageView's message queue.
|
||||
*/
|
||||
public void loadThumbnailBitmap(ImageWorkerTaskResource source,
|
||||
ImageView target) {
|
||||
loadThumbnailBitmap(source, target, target.getHeight());
|
||||
}
|
||||
/**
|
||||
* Load a bitmap from the thumbnail cache. If the bitmap is not in the
|
||||
* cache, it will be loaded from the disk. This method should either be
|
||||
* called if the ImageView's size has already been set or inside a Runnable
|
||||
* which is posted to the ImageView's message queue.
|
||||
*/
|
||||
public void loadThumbnailBitmap(ImageWorkerTaskResource source,
|
||||
ImageView target, int length) {
|
||||
final int defaultCoverResource = getDefaultCoverResource(target
|
||||
.getContext());
|
||||
final String cacheKey;
|
||||
if (source != null && (cacheKey = source.getImageLoaderCacheKey()) != null) {
|
||||
final Object currentTag = target.getTag(R.id.imageloader_key);
|
||||
if (currentTag == null || !cacheKey.equals(currentTag)) {
|
||||
target.setTag(R.id.imageloader_key, cacheKey);
|
||||
CachedBitmap cBitmap = getBitmapFromThumbnailCache(cacheKey);
|
||||
if (cBitmap != null && cBitmap.getLength() >= length) {
|
||||
target.setImageBitmap(cBitmap.getBitmap());
|
||||
} else {
|
||||
target.setImageResource(defaultCoverResource);
|
||||
BitmapDecodeWorkerTask worker = new BitmapDecodeWorkerTask(
|
||||
handler, target, source, length, IMAGE_TYPE_THUMBNAIL);
|
||||
executor.submit(worker);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
target.setImageResource(defaultCoverResource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a bitmap from the thumbnail cache. If the bitmap is not in the
|
||||
* cache, it will be loaded from the disk. This method should either be
|
||||
* called if the ImageView's size has already been set or inside a Runnable
|
||||
* which is posted to the ImageView's message queue.
|
||||
*/
|
||||
public void loadThumbnailBitmap(ImageWorkerTaskResource source,
|
||||
ImageView target, int length) {
|
||||
final int defaultCoverResource = getDefaultCoverResource(target
|
||||
.getContext());
|
||||
public void clearExecutorQueue() {
|
||||
executor.shutdownNow();
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Executor was shut down.");
|
||||
executor = createExecutor();
|
||||
|
||||
if (source != null && source.getImageLoaderCacheKey() != null) {
|
||||
target.setTag(R.id.imageloader_key, source.getImageLoaderCacheKey());
|
||||
CachedBitmap cBitmap = getBitmapFromThumbnailCache(source.getImageLoaderCacheKey());
|
||||
if (cBitmap != null && cBitmap.getLength() >= length) {
|
||||
target.setImageBitmap(cBitmap.getBitmap());
|
||||
} else {
|
||||
target.setImageResource(defaultCoverResource);
|
||||
BitmapDecodeWorkerTask worker = new BitmapDecodeWorkerTask(
|
||||
handler, target, source, length, IMAGE_TYPE_THUMBNAIL);
|
||||
executor.submit(worker);
|
||||
}
|
||||
} else {
|
||||
target.setImageResource(defaultCoverResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clearExecutorQueue() {
|
||||
executor.shutdownNow();
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Executor was shut down.");
|
||||
executor = createExecutor();
|
||||
public void wipeImageCache() {
|
||||
coverCache.evictAll();
|
||||
thumbnailCache.evictAll();
|
||||
}
|
||||
|
||||
}
|
||||
public boolean isInThumbnailCache(String fileUrl) {
|
||||
return thumbnailCache.get(fileUrl) != null;
|
||||
}
|
||||
|
||||
public void wipeImageCache() {
|
||||
coverCache.evictAll();
|
||||
thumbnailCache.evictAll();
|
||||
}
|
||||
private CachedBitmap getBitmapFromThumbnailCache(String key) {
|
||||
return thumbnailCache.get(key);
|
||||
}
|
||||
|
||||
public boolean isInThumbnailCache(String fileUrl) {
|
||||
return thumbnailCache.get(fileUrl) != null;
|
||||
}
|
||||
public void addBitmapToThumbnailCache(String key, CachedBitmap bitmap) {
|
||||
thumbnailCache.put(key, bitmap);
|
||||
}
|
||||
|
||||
private CachedBitmap getBitmapFromThumbnailCache(String key) {
|
||||
return thumbnailCache.get(key);
|
||||
}
|
||||
public boolean isInCoverCache(String fileUrl) {
|
||||
return coverCache.get(fileUrl) != null;
|
||||
}
|
||||
|
||||
public void addBitmapToThumbnailCache(String key, CachedBitmap bitmap) {
|
||||
thumbnailCache.put(key, bitmap);
|
||||
}
|
||||
private CachedBitmap getBitmapFromCoverCache(String key) {
|
||||
return coverCache.get(key);
|
||||
}
|
||||
|
||||
public boolean isInCoverCache(String fileUrl) {
|
||||
return coverCache.get(fileUrl) != null;
|
||||
}
|
||||
public void addBitmapToCoverCache(String key, CachedBitmap bitmap) {
|
||||
coverCache.put(key, bitmap);
|
||||
}
|
||||
|
||||
private CachedBitmap getBitmapFromCoverCache(String key) {
|
||||
return coverCache.get(key);
|
||||
}
|
||||
private int getDefaultCoverResource(Context context) {
|
||||
return android.R.color.transparent;
|
||||
}
|
||||
|
||||
public void addBitmapToCoverCache(String key, CachedBitmap bitmap) {
|
||||
coverCache.put(key, bitmap);
|
||||
}
|
||||
/**
|
||||
* Used by the BitmapDecodeWorker task to retrieve the source of the bitmap.
|
||||
*/
|
||||
public interface ImageWorkerTaskResource {
|
||||
/**
|
||||
* Opens a new InputStream that can be decoded as a bitmap by the
|
||||
* BitmapFactory.
|
||||
*/
|
||||
public InputStream openImageInputStream();
|
||||
|
||||
private int getDefaultCoverResource(Context context) {
|
||||
return android.R.color.transparent;
|
||||
}
|
||||
/**
|
||||
* Returns an InputStream that points to the beginning of the image
|
||||
* resource. Implementations can either create a new InputStream or
|
||||
* reset the existing one, depending on their implementation of
|
||||
* openInputStream. If a new InputStream is returned, the one given as a
|
||||
* parameter MUST be closed.
|
||||
*
|
||||
* @param input The input stream that was returned by openImageInputStream()
|
||||
*/
|
||||
public InputStream reopenImageInputStream(InputStream input);
|
||||
|
||||
/**
|
||||
* Used by the BitmapDecodeWorker task to retrieve the source of the bitmap.
|
||||
*/
|
||||
public interface ImageWorkerTaskResource {
|
||||
/**
|
||||
* Opens a new InputStream that can be decoded as a bitmap by the
|
||||
* BitmapFactory.
|
||||
*/
|
||||
public InputStream openImageInputStream();
|
||||
|
||||
/**
|
||||
* Returns an InputStream that points to the beginning of the image
|
||||
* resource. Implementations can either create a new InputStream or
|
||||
* reset the existing one, depending on their implementation of
|
||||
* openInputStream. If a new InputStream is returned, the one given as a
|
||||
* parameter MUST be closed.
|
||||
* @param input The input stream that was returned by openImageInputStream()
|
||||
* */
|
||||
public InputStream reopenImageInputStream(InputStream input);
|
||||
|
||||
/**
|
||||
* Returns a string that identifies the image resource. Example: file
|
||||
* path of an image
|
||||
*/
|
||||
public String getImageLoaderCacheKey();
|
||||
}
|
||||
/**
|
||||
* Returns a string that identifies the image resource. Example: file
|
||||
* path of an image
|
||||
*/
|
||||
public String getImageLoaderCacheKey();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user