Index: chrome/android/java/src/org/chromium/chrome/browser/ntp/interests/InterestsItemView.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/interests/InterestsItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/interests/InterestsItemView.java |
index 62d11419d7f58557c773853c43167d28ce99fc0f..4484def7d18d02e7cff3a3a8565b751c800859bd 100644 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/interests/InterestsItemView.java |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/interests/InterestsItemView.java |
@@ -24,8 +24,9 @@ import android.view.Gravity; |
import android.view.View; |
import android.view.View.OnClickListener; |
+import org.chromium.base.Callback; |
import org.chromium.base.Log; |
-import org.chromium.base.ObserverList; |
+import org.chromium.base.Promise; |
import org.chromium.base.metrics.RecordHistogram; |
import org.chromium.chrome.R; |
import org.chromium.chrome.browser.ntp.interests.InterestsPage.InterestsClickListener; |
@@ -82,7 +83,7 @@ class InterestsItemView extends AppCompatTextView implements OnClickListener { |
private final Context mContext; |
private final DrawingData mDrawingData; |
- private final LruCache<String, ImageHolder> mImageCache; |
+ private final LruCache<String, Promise<Drawable>> mImageCache; |
private final InterestsClickListener mListener; |
/** |
@@ -93,7 +94,7 @@ class InterestsItemView extends AppCompatTextView implements OnClickListener { |
* @param drawingData Information about the view size. |
*/ |
InterestsItemView(Context context, Interest interest, InterestsClickListener listener, |
- LruCache<String, ImageHolder> imageCache, DrawingData drawingData) { |
+ LruCache<String, Promise<Drawable>> imageCache, DrawingData drawingData) { |
super(context); |
mContext = context; |
@@ -132,25 +133,32 @@ class InterestsItemView extends AppCompatTextView implements OnClickListener { |
setText(mInterest.getName()); |
- ImageHolder holder = mImageCache.get(mInterest.getImageUrl()); |
- if (holder == null) { |
- // Create a new holder, add it to the cache and set it downloading. |
- holder = new ImageHolder(); |
- mImageCache.put(mInterest.getImageUrl(), holder); |
- new ImageDownloadTask(mInterest.getImageUrl(), holder, getResources()).execute(); |
+ Promise<Drawable> promise = mImageCache.get(mInterest.getImageUrl()); |
+ if (promise == null) { |
+ promise = new Promise<Drawable>(); |
+ mImageCache.put(mInterest.getImageUrl(), |
+ ImageDownloadTask.start(mInterest.getImageUrl(), getResources())); |
} |
- if (holder.getImageDrawable() != null) { |
- setImage(holder.getImageDrawable()); |
- } else { |
- // Add a callback to a subclass that will call setImage once the holder is filled. |
- holder.addListener(new ImageDownloadedCallback()); |
- |
- // Display a letter tile in the meantime. |
+ // If not fulfilled, display a letter tile while waiting for the image to download. |
+ if (!promise.isFulfilled()) { |
mDrawingData.mIconGenerator.setBackgroundColor(getTileColor(mInterest.getName())); |
setImage(new BitmapDrawable(mContext.getResources(), |
mDrawingData.mIconGenerator.generateIconForText(mInterest.getName()))); |
} |
+ |
+ // Once fulfilled, display the image (unless this view has been repurposed for a different |
+ // Interest). |
+ final String urlWhenDownloadRequested = mInterest.getImageUrl(); |
+ promise.then(new Callback<Drawable>() { |
+ @Override |
+ public void onResult(Drawable drawable) { |
+ if (drawable == null) return; |
+ if (TextUtils.equals(mInterest.getImageUrl(), urlWhenDownloadRequested)) return; |
+ |
+ setImage(drawable); |
+ } |
+ }); |
} |
/** |
@@ -184,17 +192,23 @@ class InterestsItemView extends AppCompatTextView implements OnClickListener { |
} |
/* |
- * An AsyncTask that downloads an image, formats it then puts it in the given holder. |
+ * An AsyncTask that downloads an image and formats it. |
*/ |
private static class ImageDownloadTask extends AsyncTask<Void, Void, Drawable> { |
+ public static Promise<Drawable> start(String url, Resources resources) { |
+ Promise<Drawable> promise = new Promise<Drawable>(); |
+ new ImageDownloadTask(url, promise, resources).executeOnExecutor(THREAD_POOL_EXECUTOR); |
+ return promise; |
+ } |
+ |
private final String mUrl; |
- private final ImageHolder mImageHolder; |
private final Resources mResources; |
+ private Promise<Drawable> mPromise; |
- public ImageDownloadTask(String url, ImageHolder holder, Resources resources) { |
+ private ImageDownloadTask(String url, Promise<Drawable> promise, Resources resources) { |
mUrl = url; |
- mImageHolder = holder; |
+ mPromise = promise; |
mResources = resources; |
} |
@@ -221,60 +235,9 @@ class InterestsItemView extends AppCompatTextView implements OnClickListener { |
@Override |
protected void onPostExecute(Drawable image) { |
- // This is run on the main thread. |
- mImageHolder.set(image, mUrl); |
- } |
- } |
- |
- /* |
- * A callback class that will set it's parent's image. |
- */ |
- private class ImageDownloadedCallback { |
- public void onImageDownloaded(Drawable image, String url) { |
- boolean imageDownloadSuccess = image != null; |
RecordHistogram.recordBooleanHistogram( |
- "NewTabPage.Interests.ImageDownloadSuccess", imageDownloadSuccess); |
- if (!imageDownloadSuccess) return; |
- // If the Interest this View is displaying has changed while downloading, do not update |
- // the image. |
- if (TextUtils.equals(url, mInterest.getImageUrl())) { |
- setImage(image); |
- } |
- } |
- } |
- |
- /* |
- * A holder for an Image that allows listeners to subscribe to when it is set. It is |
- * like a listenable future that doesn't calculate the value itself. It can only be |
- * accessed on one thread. It can only be set once. |
- */ |
- static class ImageHolder { |
- private final ObserverList<ImageDownloadedCallback> mCallbacks = new ObserverList<>(); |
- private Drawable mImage; |
- private String mUrl; |
- |
- public void set(Drawable image, String url) { |
- assert mImage == null; |
- mImage = image; |
- mUrl = url; |
- |
- for (ImageDownloadedCallback callbacks : mCallbacks) { |
- callbacks.onImageDownloaded(image, mUrl); |
- } |
- |
- mCallbacks.clear(); |
- } |
- |
- public void addListener(ImageDownloadedCallback callback) { |
- if (mImage == null) { |
- mCallbacks.addObserver(callback); |
- } else { |
- callback.onImageDownloaded(mImage, mUrl); |
- } |
- } |
- |
- public Drawable getImageDrawable() { |
- return mImage; |
+ "NewTabPage.Interests.ImageDownloadSuccess", image != null); |
+ mPromise.fulfill(image); |
} |
} |
} |