mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-22 07:57:30 +00:00
Better asynchronous loading for Recipient information.
1) Switch back from AsyncTasks to an Executor and Futures. 2) Make the Executor operate LIFO. 3) Make the Executor thread a BACKGROUND_PRIORITY thread.
This commit is contained in:
parent
9939830551
commit
9b45e6068b
@ -20,8 +20,11 @@ import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Log;
|
||||
|
||||
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;
|
||||
|
||||
@ -46,38 +49,33 @@ public class Recipient implements Parcelable {
|
||||
private RecipientModifiedListener listener;
|
||||
private boolean asynchronousUpdateComplete = false;
|
||||
|
||||
// public Recipient(String name, String number, Uri contactUri, Bitmap contactPhoto) {
|
||||
// this(name, number, contactPhoto);
|
||||
// this.contactUri = contactUri;
|
||||
// }
|
||||
public Recipient(String number, Bitmap contactPhoto,
|
||||
ListenableFutureTask<RecipientDetails> future)
|
||||
{
|
||||
this.number = number;
|
||||
this.contactPhoto.set(contactPhoto);
|
||||
|
||||
// public Recipient(String number, Bitmap contactPhoto,
|
||||
// ListenableFutureTask<RecipientDetails> future)
|
||||
// {
|
||||
// this.number = number;
|
||||
// this.contactUri = null;
|
||||
// this.contactPhoto.set(contactPhoto);
|
||||
//
|
||||
// future.setListener(new FutureTaskListener<RecipientDetails>() {
|
||||
// @Override
|
||||
// public void onSuccess(RecipientDetails result) {
|
||||
// if (result != null) {
|
||||
// Recipient.this.name.set(result.name);
|
||||
// Recipient.this.contactPhoto.set(result.avatar);
|
||||
//
|
||||
// synchronized(this) {
|
||||
// if (listener == null) asynchronousUpdateComplete = true;
|
||||
// else listener.onModified(Recipient.this);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onFailure(Throwable error) {
|
||||
// Log.w("Recipient", error);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
future.setListener(new FutureTaskListener<RecipientDetails>() {
|
||||
@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);
|
||||
|
||||
synchronized(this) {
|
||||
if (listener == null) asynchronousUpdateComplete = true;
|
||||
else listener.onModified(Recipient.this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable error) {
|
||||
Log.w("Recipient", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Recipient(String name, String number, Uri contactUri, Bitmap contactPhoto) {
|
||||
this.number = number;
|
||||
@ -110,18 +108,18 @@ public class Recipient implements Parcelable {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void updateAsynchronousContent(RecipientDetails result) {
|
||||
if (result != null) {
|
||||
Recipient.this.name.set(result.name);
|
||||
Recipient.this.contactUri.set(result.contactUri);
|
||||
Recipient.this.contactPhoto.set(result.avatar);
|
||||
|
||||
synchronized(this) {
|
||||
if (listener == null) asynchronousUpdateComplete = true;
|
||||
else listener.onModified(Recipient.this);
|
||||
}
|
||||
}
|
||||
}
|
||||
// public void updateAsynchronousContent(RecipientDetails result) {
|
||||
// if (result != null) {
|
||||
// Recipient.this.name.set(result.name);
|
||||
// Recipient.this.contactUri.set(result.contactUri);
|
||||
// Recipient.this.contactPhoto.set(result.avatar);
|
||||
//
|
||||
// synchronized(this) {
|
||||
// if (listener == null) asynchronousUpdateComplete = true;
|
||||
// else listener.onModified(Recipient.this);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
public synchronized void setListener(RecipientModifiedListener listener) {
|
||||
this.listener = listener;
|
||||
|
@ -21,22 +21,27 @@ import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Process;
|
||||
import android.provider.ContactsContract;
|
||||
import android.provider.ContactsContract.Contacts;
|
||||
import android.provider.ContactsContract.PhoneLookup;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.util.LRUCache;
|
||||
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class RecipientProvider {
|
||||
|
||||
private static final Map<String,Recipient> recipientCache = Collections.synchronizedMap(new LRUCache<String,Recipient>(1000));
|
||||
// private static final ExecutorService asyncRecipientResolver = Executors.newSingleThreadExecutor();
|
||||
private static final ExecutorService asyncRecipientResolver = Util.newSingleThreadedLifoExecutor();
|
||||
|
||||
private static final String[] CALLER_ID_PROJECTION = new String[] {
|
||||
PhoneLookup.DISPLAY_NAME,
|
||||
@ -70,70 +75,43 @@ public class RecipientProvider {
|
||||
private Recipient getAsynchronousRecipient(final Context context, final String number) {
|
||||
Log.w("RecipientProvider", "Cache miss [ASYNC]!");
|
||||
|
||||
Recipient recipient = new Recipient(null, number, null, ContactPhotoFactory.getDefaultContactPhoto(context));
|
||||
recipientCache.put(number, recipient);
|
||||
|
||||
new AsyncTask<Recipient, Void, RecipientDetails>() {
|
||||
private Recipient recipient;
|
||||
|
||||
@Override
|
||||
protected RecipientDetails doInBackground(Recipient... recipient) {
|
||||
this.recipient = recipient[0];
|
||||
return getRecipientDetails(context, number);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(RecipientDetails result) {
|
||||
recipient.updateAsynchronousContent(result);
|
||||
}
|
||||
}.execute(recipient);
|
||||
|
||||
return recipient;
|
||||
|
||||
// ListenableFutureTask<RecipientDetails> future =
|
||||
// new ListenableFutureTask<RecipientDetails>(new Callable<RecipientDetails>() {
|
||||
// @Override
|
||||
// public RecipientDetails call() throws Exception {
|
||||
// return getRecipientDetails(context, number);
|
||||
//// RecipientDetails recipientDetails = getRecipientDetails();
|
||||
////
|
||||
//// if (recipientDeta)
|
||||
////
|
||||
//// Recipient cachedRecipient = recipientCache.get(number);
|
||||
////
|
||||
//// if (cachedRecipient != null) {
|
||||
//// return new RecipientDetails(cachedRecipient.getName(), cachedRecipient.getContactPhoto());
|
||||
//// }
|
||||
////
|
||||
//// Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
|
||||
//// Cursor cursor = context.getContentResolver().query(uri, CALLER_ID_PROJECTION,
|
||||
//// null, null, null);
|
||||
////
|
||||
//// try {
|
||||
//// if (cursor != null && cursor.moveToFirst()) {
|
||||
//// Uri contactUri = Contacts.getLookupUri(cursor.getLong(2), cursor.getString(1));
|
||||
//// Bitmap contactPhoto = getContactPhoto(context, Uri.withAppendedPath(Contacts.CONTENT_URI,
|
||||
//// cursor.getLong(2)+""));
|
||||
////
|
||||
//// recipientCache.put(number, new Recipient(cursor.getString(0), number, contactPhoto));
|
||||
//// return new RecipientDetails(cursor.getString(0), contactPhoto);
|
||||
//// } else {
|
||||
//// recipientCache.put(number, new Recipient(null, number, ContactPhotoFactory.getDefaultContactPhoto(context)));
|
||||
//// }
|
||||
//// } finally {
|
||||
//// if (cursor != null)
|
||||
//// cursor.close();
|
||||
//// }
|
||||
////
|
||||
//// return null;
|
||||
// }
|
||||
// }, null);
|
||||
//
|
||||
// asyncRecipientResolver.submit(future);
|
||||
// Recipient recipient = new Recipient(number, ContactPhotoFactory.getDefaultContactPhoto(context), future);
|
||||
// Recipient recipient = new Recipient(null, number, null, ContactPhotoFactory.getDefaultContactPhoto(context));
|
||||
// recipientCache.put(number, recipient);
|
||||
//
|
||||
// new AsyncTask<Recipient, Void, RecipientDetails>() {
|
||||
// private Recipient recipient;
|
||||
//
|
||||
// @Override
|
||||
// protected RecipientDetails doInBackground(Recipient... recipient) {
|
||||
// this.recipient = recipient[0];
|
||||
// return getRecipientDetails(context, number);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected void onPostExecute(RecipientDetails result) {
|
||||
// recipient.updateAsynchronousContent(result);
|
||||
// }
|
||||
// }.execute(recipient);
|
||||
//
|
||||
// return recipient;
|
||||
|
||||
// ListenableFutureTask<RecipientDetails> future = new ListenableFutureTask<RecipientDetails>(new Callable<RecipientDetails>() {
|
||||
Callable<RecipientDetails> task = new Callable<RecipientDetails>() {
|
||||
@Override
|
||||
public RecipientDetails call() throws Exception {
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
||||
return getRecipientDetails(context, number);
|
||||
}
|
||||
};
|
||||
|
||||
ListenableFutureTask<RecipientDetails> future = new ListenableFutureTask<RecipientDetails>(task, null);
|
||||
|
||||
asyncRecipientResolver.submit(future);
|
||||
|
||||
Recipient recipient = new Recipient(number, ContactPhotoFactory.getDefaultContactPhoto(context), future);
|
||||
recipientCache.put(number, recipient);
|
||||
|
||||
return recipient;
|
||||
//// return new Recipient(null, number, ContactPhotoFactory.getDefaultContactPhoto(context));
|
||||
}
|
||||
|
||||
|
1191
src/org/thoughtcrime/securesms/util/LinkedBlockingDeque.java
Normal file
1191
src/org/thoughtcrime/securesms/util/LinkedBlockingDeque.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,20 @@
|
||||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
public class LinkedBlockingLifoQueue<E> extends LinkedBlockingDeque<E> {
|
||||
@Override
|
||||
public void put(E runnable) throws InterruptedException {
|
||||
super.putFirst(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E runnable) {
|
||||
super.addFirst(runnable);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offer(E runnable) {
|
||||
super.addFirst(runnable);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -16,6 +16,10 @@
|
||||
*/
|
||||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class Util {
|
||||
|
||||
public static byte[] combine(byte[] one, byte[] two) {
|
||||
@ -62,6 +66,10 @@ public class Util {
|
||||
return splitString;
|
||||
}
|
||||
|
||||
public static ExecutorService newSingleThreadedLifoExecutor() {
|
||||
return new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingLifoQueue<Runnable>());
|
||||
}
|
||||
|
||||
// public static Bitmap loadScaledBitmap(InputStream src, int targetWidth, int targetHeight) {
|
||||
// return BitmapFactory.decodeStream(src);
|
||||
//// BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
|
Loading…
x
Reference in New Issue
Block a user