aboutsummaryrefslogtreecommitdiff
path: root/src/com/android/tv/util/ImageLoader.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/tv/util/ImageLoader.java')
-rw-r--r--src/com/android/tv/util/ImageLoader.java46
1 files changed, 42 insertions, 4 deletions
diff --git a/src/com/android/tv/util/ImageLoader.java b/src/com/android/tv/util/ImageLoader.java
index 59c4983b..ed0fd54d 100644
--- a/src/com/android/tv/util/ImageLoader.java
+++ b/src/com/android/tv/util/ImageLoader.java
@@ -28,18 +28,23 @@ import android.support.annotation.MainThread;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.annotation.WorkerThread;
+import android.util.ArraySet;
import android.util.Log;
import com.android.tv.R;
-import com.android.tv.common.CollectionUtils;
import com.android.tv.util.BitmapUtils.ScaledBitmapInfo;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
+import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
/**
* This class wraps up completing some arbitrary long running work when loading a bitmap. It
@@ -49,6 +54,39 @@ public final class ImageLoader {
private static final String TAG = "ImageLoader";
private static final boolean DEBUG = false;
+ private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
+ // We want at least 2 threads and at most 4 threads in the core pool,
+ // preferring to have 1 less than the CPU count to avoid saturating
+ // the CPU with background work
+ private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
+ private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
+ private static final int KEEP_ALIVE_SECONDS = 30;
+
+ private static final ThreadFactory sThreadFactory = new NamedThreadFactory("ImageLoader");
+
+ private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(
+ 128);
+
+ /**
+ * An private {@link Executor} that can be used to execute tasks in parallel.
+ *
+ * <p>{@code IMAGE_THREAD_POOL_EXECUTOR} setting are copied from {@link AsyncTask}
+ * Since we do a lot of concurrent image loading we can exhaust a thread pool.
+ * ImageLoader catches the error, and just leaves the image blank.
+ * However other tasks will fail and crash the application.
+ *
+ * <p>Using a separate thread pool prevents image loading from causing other tasks to fail.
+ */
+ private static final Executor IMAGE_THREAD_POOL_EXECUTOR;
+
+ static {
+ ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
+ MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, sPoolWorkQueue,
+ sThreadFactory);
+ threadPoolExecutor.allowCoreThreadTimeOut(true);
+ IMAGE_THREAD_POOL_EXECUTOR = threadPoolExecutor;
+ }
+
private static Handler sMainHandler;
/**
@@ -148,7 +186,7 @@ public final class ImageLoader {
Log.d(TAG, "loadBitmap() " + uriString);
}
return doLoadBitmap(context, uriString, maxWidth, maxHeight, callback,
- AsyncTask.THREAD_POOL_EXECUTOR);
+ IMAGE_THREAD_POOL_EXECUTOR);
}
private static boolean doLoadBitmap(Context context, String uriString,
@@ -179,7 +217,7 @@ public final class ImageLoader {
if (DEBUG) {
Log.d(TAG, "loadBitmap() " + loadBitmapTask);
}
- return doLoadBitmap(callback, AsyncTask.THREAD_POOL_EXECUTOR, loadBitmapTask);
+ return doLoadBitmap(callback, IMAGE_THREAD_POOL_EXECUTOR, loadBitmapTask);
}
/**
@@ -226,7 +264,7 @@ public final class ImageLoader {
protected final Context mAppContext;
protected final int mMaxWidth;
protected final int mMaxHeight;
- private final Set<ImageLoaderCallback> mCallbacks = CollectionUtils.createSmallSet();
+ private final Set<ImageLoaderCallback> mCallbacks = new ArraySet<>();
private final ImageCache mImageCache;
private final String mKey;