diff --git a/src/org/thoughtcrime/securesms/ConversationListAdapter.java b/src/org/thoughtcrime/securesms/ConversationListAdapter.java index ca61004ad5..d0a23903d5 100644 --- a/src/org/thoughtcrime/securesms/ConversationListAdapter.java +++ b/src/org/thoughtcrime/securesms/ConversationListAdapter.java @@ -21,6 +21,7 @@ import android.database.Cursor; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.AbsListView; import android.widget.CursorAdapter; import org.thoughtcrime.securesms.database.DatabaseFactory; @@ -38,7 +39,7 @@ import java.util.Set; * * @author Moxie Marlinspike */ -public class ConversationListAdapter extends CursorAdapter { +public class ConversationListAdapter extends CursorAdapter implements AbsListView.RecyclerListener { private final Context context; private final LayoutInflater inflater; @@ -114,4 +115,9 @@ public class ConversationListAdapter extends CursorAdapter { this.notifyDataSetChanged(); } + + @Override + public void onMovedToScrapHeap(View view) { + ((ConversationListItem)view).unbind(); + } } diff --git a/src/org/thoughtcrime/securesms/ConversationListFragment.java b/src/org/thoughtcrime/securesms/ConversationListFragment.java index e425aeae47..47a3061750 100644 --- a/src/org/thoughtcrime/securesms/ConversationListFragment.java +++ b/src/org/thoughtcrime/securesms/ConversationListFragment.java @@ -143,6 +143,7 @@ private void initializeSearch(android.widget.SearchView searchView) { this.setListAdapter(new DecryptingConversationListAdapter(getActivity(), null, masterSecret)); } + getListView().setRecyclerListener((ConversationListAdapter)getListAdapter()); getLoaderManager().restartLoader(0, null, this); } diff --git a/src/org/thoughtcrime/securesms/ConversationListItem.java b/src/org/thoughtcrime/securesms/ConversationListItem.java index 692422de1a..801a201c8a 100644 --- a/src/org/thoughtcrime/securesms/ConversationListItem.java +++ b/src/org/thoughtcrime/securesms/ConversationListItem.java @@ -103,6 +103,7 @@ public class ConversationListItem extends RelativeLayout this.count = thread.getCount(); this.read = thread.isRead(); + this.recipients.addListener(this); this.fromView.setText(formatFrom(recipients, count, read)); if (thread.isKeyExchange()) @@ -124,7 +125,10 @@ public class ConversationListItem extends RelativeLayout else checkbox.setVisibility(View.GONE); setContactPhoto(this.recipients.getPrimaryRecipient()); - this.recipients.setListener(this); + } + + public void unbind() { + this.recipients.removeListener(this); } private void intializeListeners() { diff --git a/src/org/thoughtcrime/securesms/recipients/Recipient.java b/src/org/thoughtcrime/securesms/recipients/Recipient.java index 07d3e3a731..3aa2b95b5d 100644 --- a/src/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/src/org/thoughtcrime/securesms/recipients/Recipient.java @@ -26,7 +26,7 @@ import org.thoughtcrime.securesms.recipients.RecipientProvider.RecipientDetails; import org.thoughtcrime.securesms.util.FutureTaskListener; import org.thoughtcrime.securesms.util.ListenableFutureTask; -import java.util.concurrent.atomic.AtomicReference; +import java.util.HashSet; public class Recipient implements Parcelable { @@ -40,33 +40,35 @@ public class Recipient implements Parcelable { } }; - private final AtomicReference name = new AtomicReference(null); - private final AtomicReference contactPhoto = new AtomicReference(null); - private final AtomicReference contactUri = new AtomicReference(null); - private final String number; + private final HashSet listeners = new HashSet(); - private RecipientModifiedListener listener; - private boolean asynchronousUpdateComplete = false; + private String name; + private Bitmap contactPhoto; + private Uri contactUri; public Recipient(String number, Bitmap contactPhoto, ListenableFutureTask future) { - this.number = number; - this.contactPhoto.set(contactPhoto); + this.number = number; + this.contactPhoto = contactPhoto; future.setListener(new FutureTaskListener() { @Override public void onSuccess(RecipientDetails result) { if (result != null) { - Recipient.this.name.set(result.name); - Recipient.this.contactUri.set(result.contactUri); - Recipient.this.contactPhoto.set(result.avatar); + HashSet localListeners; - synchronized(this) { - if (listener == null) asynchronousUpdateComplete = true; - else listener.onModified(Recipient.this); + synchronized (Recipient.this) { + Recipient.this.name = result.name; + Recipient.this.contactUri = result.contactUri; + Recipient.this.contactPhoto = result.avatar; + localListeners = (HashSet)listeners.clone(); + listeners.clear(); } + + for (RecipientModifiedListener listener : localListeners) + listener.onModified(Recipient.this); } } @@ -78,26 +80,25 @@ public class Recipient implements Parcelable { } public Recipient(String name, String number, Uri contactUri, Bitmap contactPhoto) { - this.number = number; - this.contactUri.set(contactUri); - this.name.set(name); - this.contactPhoto.set(contactPhoto); + this.number = number; + this.contactUri = contactUri; + this.name = name; + this.contactPhoto = contactPhoto; } public Recipient(Parcel in) { - this.number = in.readString(); - - this.name.set(in.readString()); - this.contactUri.set((Uri)in.readParcelable(null)); - this.contactPhoto.set((Bitmap)in.readParcelable(null)); + this.number = in.readString(); + this.name = in.readString(); + this.contactUri = (Uri)in.readParcelable(null); + this.contactPhoto = (Bitmap)in.readParcelable(null); } - public Uri getContactUri() { - return this.contactUri.get(); + public synchronized Uri getContactUri() { + return this.contactUri; } - public String getName() { - return name.get(); + public synchronized String getName() { + return this.name; } public String getNumber() { @@ -121,28 +122,27 @@ public class Recipient implements Parcelable { // } // } - public synchronized void setListener(RecipientModifiedListener listener) { - this.listener = listener; - if (asynchronousUpdateComplete) { - if (listener != null) - listener.onModified(this); - asynchronousUpdateComplete = false; - } + public synchronized void addListener(RecipientModifiedListener listener) { + listeners.add(listener); } - public void writeToParcel(Parcel dest, int flags) { + public synchronized void removeListener(RecipientModifiedListener listener) { + listeners.remove(listener); + } + + public synchronized void writeToParcel(Parcel dest, int flags) { dest.writeString(number); - dest.writeString(name.get()); - dest.writeParcelable(contactUri.get(), 0); - dest.writeParcelable(contactPhoto.get(), 0); + dest.writeString(name); + dest.writeParcelable(contactUri, 0); + dest.writeParcelable(contactPhoto, 0); } - public String toShortString() { - return (name.get() == null ? number : name.get()); + public synchronized String toShortString() { + return (name == null ? number : name); } - public Bitmap getContactPhoto() { - return contactPhoto.get(); + public synchronized Bitmap getContactPhoto() { + return contactPhoto; } public static interface RecipientModifiedListener { diff --git a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java index daecba17bd..87c0a16b49 100644 --- a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java +++ b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java @@ -21,7 +21,6 @@ import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; -import android.os.Process; import android.provider.ContactsContract; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.PhoneLookup; @@ -100,7 +99,7 @@ public class RecipientProvider { Callable task = new Callable() { @Override public RecipientDetails call() throws Exception { - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); +// Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); return getRecipientDetails(context, number); } }; diff --git a/src/org/thoughtcrime/securesms/recipients/Recipients.java b/src/org/thoughtcrime/securesms/recipients/Recipients.java index 52b24e7d4d..43e3eb1efe 100644 --- a/src/org/thoughtcrime/securesms/recipients/Recipients.java +++ b/src/org/thoughtcrime/securesms/recipients/Recipients.java @@ -69,9 +69,15 @@ public class Recipients implements Parcelable { return this; } - public void setListener(RecipientModifiedListener listener) { + public void addListener(RecipientModifiedListener listener) { for (Recipient recipient : recipients) { - recipient.setListener(listener); + recipient.addListener(listener); + } + } + + public void removeListener(RecipientModifiedListener listener) { + for (Recipient recipient : recipients) { + recipient.removeListener(listener); } } diff --git a/src/org/thoughtcrime/securesms/util/Util.java b/src/org/thoughtcrime/securesms/util/Util.java index 12663782f7..d6c71a479e 100644 --- a/src/org/thoughtcrime/securesms/util/Util.java +++ b/src/org/thoughtcrime/securesms/util/Util.java @@ -67,7 +67,17 @@ public class Util { } public static ExecutorService newSingleThreadedLifoExecutor() { - return new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingLifoQueue()); + ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingLifoQueue()); + + executor.execute(new Runnable() { + @Override + public void run() { +// Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + Thread.currentThread().setPriority(Thread.MIN_PRIORITY); + } + }); + + return executor; } // public static Bitmap loadScaledBitmap(InputStream src, int targetWidth, int targetHeight) {