Allow a custom and dedicated executor to be used for tile loading
diff --git a/library/src/main/java/com/davemorrissey/labs/subscaleview/SubsamplingScaleImageView.java b/library/src/main/java/com/davemorrissey/labs/subscaleview/SubsamplingScaleImageView.java
index a9718b3..b28d8a7 100644
--- a/library/src/main/java/com/davemorrissey/labs/subscaleview/SubsamplingScaleImageView.java
+++ b/library/src/main/java/com/davemorrissey/labs/subscaleview/SubsamplingScaleImageView.java
@@ -46,6 +46,7 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.concurrent.Executor;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -173,8 +174,8 @@
private int maxTileWidth = TILE_SIZE_AUTO;
private int maxTileHeight = TILE_SIZE_AUTO;
- // Whether to use the thread pool executor to load tiles
- private boolean parallelLoadingEnabled;
+ // An executor service for loading of images
+ private Executor executor = AsyncTask.SERIAL_EXECUTOR;
// Gesture detection settings
private boolean panEnabled = true;
@@ -1846,11 +1847,7 @@
}
private void execute(AsyncTask<Void, Void, ?> asyncTask) {
- if (parallelLoadingEnabled) {
- asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- } else {
- asyncTask.execute();
- }
+ asyncTask.executeOnExecutor(executor);
}
private static class Tile {
@@ -2750,13 +2747,29 @@
}
/**
- * Toggle parallel loading. When enabled, tiles are loaded using the thread pool executor.
- * Parallel loading may use more memory and there is a possibility that it will make the tile
- * loading unreliable, but it reduces the chances of an app's background processes blocking loading.
- * @param parallelLoadingEnabled Whether to run AsyncTasks using a thread pool executor.
+ * <p>
+ * Provide an {@link Executor} to be used for loading images. By default, {@link AsyncTask#SERIAL_EXECUTOR}
+ * is used, and this can cause slow loading when this executor is being used for other tasks e.g.
+ * loading data from the network. You can use {@link AsyncTask#THREAD_POOL_EXECUTOR} to reduce
+ * the likelihood of contention, or supply an {@link Executor} of your own to avoid any contention.
+ * It is strongly recommended to use a single executor instance for the life of your application,
+ * not one per view instance.
+ * </p><p>
+ * <b>Warning:</b> If you are using a custom implementation of {@link ImageRegionDecoder}, and you
+ * supply an executor with more than one thread, you must make sure your implementation supports
+ * multi-threaded bitmap decoding or has appropriate internal synchronization. Android's
+ * {@link android.graphics.BitmapRegionDecoder} uses an internal lock so it is thread safe but
+ * there is no advantage to using multiple threads.
+ * </p><p>
+ * <b>Note:</b> Using an executor with multiple threads may increase memory usage.
+ * </p>
+ * @param executor an {@link Executor} for image loading.
*/
- public void setParallelLoadingEnabled(boolean parallelLoadingEnabled) {
- this.parallelLoadingEnabled = parallelLoadingEnabled;
+ public void setExecutor(Executor executor) {
+ if (executor == null) {
+ throw new NullPointerException("Executor must not be null");
+ }
+ this.executor = executor;
}
/**