Use a thread pool to fetch images. Bug 2163087.
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index c4ef60f..78ab07e 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -111,6 +111,9 @@
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
/*TODO(emillar) I commented most of the code that deals with modes and filtering. It should be
* brought back in as we add back that functionality.
@@ -389,6 +392,8 @@
private static final int CONTACTS_ID = 1001;
private static final UriMatcher sContactsIdMatcher;
+ private static ExecutorService sImageFetchThreadPool;
+
static {
sContactsIdMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sContactsIdMatcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID);
@@ -2021,6 +2026,7 @@
private Cursor mSuggestionsCursor;
private int mSuggestionsCursorCount;
private ImageFetchHandler mHandler;
+ private ImageDbFetcher mImageFetcher;
private static final int FETCH_IMAGE_MSG = 1;
public ContactItemListAdapter(Context context) {
@@ -2095,18 +2101,11 @@
break;
}
- Bitmap photo = null;
- try {
- photo = ContactsUtils.loadContactPhoto(mContext, photoId, null);
- } catch (OutOfMemoryError e) {
- // Not enough memory for the photo, do nothing.
- }
+ Bitmap photo = mBitmapCache.get(photoId).get();
if (photo == null) {
break;
}
- mBitmapCache.put(photoId, new SoftReference<Bitmap>(photo));
-
// Make sure the photoId on this image view has not changed
// while we were loading the image.
synchronized (imageView) {
@@ -2127,6 +2126,50 @@
}
}
+ private class ImageDbFetcher implements Runnable {
+ long mPhotoId;
+ private ImageView mImageView;
+
+ public ImageDbFetcher(long photoId, ImageView imageView) {
+ this.mPhotoId = photoId;
+ this.mImageView = imageView;
+ }
+
+ public void run() {
+ if (ContactsListActivity.this.isFinishing()) {
+ return;
+ }
+
+ if (Thread.currentThread().interrupted()) {
+ // shutdown has been called.
+ return;
+ }
+ Bitmap photo = null;
+ try {
+ photo = ContactsUtils.loadContactPhoto(mContext, mPhotoId, null);
+ } catch (OutOfMemoryError e) {
+ // Not enough memory for the photo, do nothing.
+ }
+
+ if (photo == null) {
+ return;
+ }
+
+ mBitmapCache.put(mPhotoId, new SoftReference<Bitmap>(photo));
+
+ if (Thread.currentThread().interrupted()) {
+ // shutdown has been called.
+ return;
+ }
+
+ // Update must happen on UI thread
+ Message msg = new Message();
+ msg.what = FETCH_IMAGE_MSG;
+ msg.obj = mImageView;
+ mHandler.sendMessage(msg);
+ }
+ }
+
public void setSuggestionsCursor(Cursor cursor) {
if (mSuggestionsCursor != null) {
mSuggestionsCursor.close();
@@ -2775,14 +2818,42 @@
}
private void sendFetchImageMessage(ImageView view) {
- Message msg = new Message();
- msg.what = FETCH_IMAGE_MSG;
- msg.obj = view;
- mHandler.sendMessage(msg);
+ final PhotoInfo info = (PhotoInfo) view.getTag();
+ if (info == null) {
+ return;
+ }
+ final long photoId = info.photoId;
+ if (photoId == 0) {
+ return;
+ }
+ mImageFetcher = new ImageDbFetcher(photoId, view);
+ synchronized (ContactsListActivity.this) {
+ // can't sync on sImageFetchThreadPool.
+ if (sImageFetchThreadPool == null) {
+ // Don't use more than 3 threads at a time to update. The thread pool will be
+ // shared by all contact items.
+ sImageFetchThreadPool = Executors.newFixedThreadPool(3);
+ }
+ sImageFetchThreadPool.execute(mImageFetcher);
+ }
}
- /** Clear all pending messages on the {@link ImageFetchHandler} */
+
+ /**
+ * Stop the image fetching for ALL contacts, if one is in progress we'll
+ * not query the database.
+ *
+ * TODO: move this method to ContactsListActivity, it does not apply to the current
+ * contact.
+ */
public void clearImageFetching() {
+ synchronized (ContactsListActivity.this) {
+ if (sImageFetchThreadPool != null) {
+ sImageFetchThreadPool.shutdownNow();
+ sImageFetchThreadPool = null;
+ }
+ }
+
mHandler.clearImageFecthing();
}
}