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.net.Uri;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientProvider.RecipientDetails;
|
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.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
@ -46,38 +49,33 @@ public class Recipient implements Parcelable {
|
|||||||
private RecipientModifiedListener listener;
|
private RecipientModifiedListener listener;
|
||||||
private boolean asynchronousUpdateComplete = false;
|
private boolean asynchronousUpdateComplete = false;
|
||||||
|
|
||||||
// public Recipient(String name, String number, Uri contactUri, Bitmap contactPhoto) {
|
public Recipient(String number, Bitmap contactPhoto,
|
||||||
// this(name, number, contactPhoto);
|
ListenableFutureTask<RecipientDetails> future)
|
||||||
// this.contactUri = contactUri;
|
{
|
||||||
// }
|
this.number = number;
|
||||||
|
this.contactPhoto.set(contactPhoto);
|
||||||
|
|
||||||
// public Recipient(String number, Bitmap contactPhoto,
|
future.setListener(new FutureTaskListener<RecipientDetails>() {
|
||||||
// ListenableFutureTask<RecipientDetails> future)
|
@Override
|
||||||
// {
|
public void onSuccess(RecipientDetails result) {
|
||||||
// this.number = number;
|
if (result != null) {
|
||||||
// this.contactUri = null;
|
Recipient.this.name.set(result.name);
|
||||||
// this.contactPhoto.set(contactPhoto);
|
Recipient.this.contactUri.set(result.contactUri);
|
||||||
//
|
Recipient.this.contactPhoto.set(result.avatar);
|
||||||
// future.setListener(new FutureTaskListener<RecipientDetails>() {
|
|
||||||
// @Override
|
synchronized(this) {
|
||||||
// public void onSuccess(RecipientDetails result) {
|
if (listener == null) asynchronousUpdateComplete = true;
|
||||||
// if (result != null) {
|
else listener.onModified(Recipient.this);
|
||||||
// Recipient.this.name.set(result.name);
|
}
|
||||||
// Recipient.this.contactPhoto.set(result.avatar);
|
}
|
||||||
//
|
}
|
||||||
// synchronized(this) {
|
|
||||||
// if (listener == null) asynchronousUpdateComplete = true;
|
@Override
|
||||||
// else listener.onModified(Recipient.this);
|
public void onFailure(Throwable error) {
|
||||||
// }
|
Log.w("Recipient", error);
|
||||||
// }
|
}
|
||||||
// }
|
});
|
||||||
//
|
}
|
||||||
// @Override
|
|
||||||
// public void onFailure(Throwable error) {
|
|
||||||
// Log.w("Recipient", error);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
public Recipient(String name, String number, Uri contactUri, Bitmap contactPhoto) {
|
public Recipient(String name, String number, Uri contactUri, Bitmap contactPhoto) {
|
||||||
this.number = number;
|
this.number = number;
|
||||||
@ -110,18 +108,18 @@ public class Recipient implements Parcelable {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateAsynchronousContent(RecipientDetails result) {
|
// public void updateAsynchronousContent(RecipientDetails result) {
|
||||||
if (result != null) {
|
// if (result != null) {
|
||||||
Recipient.this.name.set(result.name);
|
// Recipient.this.name.set(result.name);
|
||||||
Recipient.this.contactUri.set(result.contactUri);
|
// Recipient.this.contactUri.set(result.contactUri);
|
||||||
Recipient.this.contactPhoto.set(result.avatar);
|
// Recipient.this.contactPhoto.set(result.avatar);
|
||||||
|
//
|
||||||
synchronized(this) {
|
// synchronized(this) {
|
||||||
if (listener == null) asynchronousUpdateComplete = true;
|
// if (listener == null) asynchronousUpdateComplete = true;
|
||||||
else listener.onModified(Recipient.this);
|
// else listener.onModified(Recipient.this);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
public synchronized void setListener(RecipientModifiedListener listener) {
|
public synchronized void setListener(RecipientModifiedListener listener) {
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
|
@ -21,22 +21,27 @@ import android.database.Cursor;
|
|||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.Process;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
import android.provider.ContactsContract.Contacts;
|
import android.provider.ContactsContract.Contacts;
|
||||||
import android.provider.ContactsContract.PhoneLookup;
|
import android.provider.ContactsContract.PhoneLookup;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.util.LRUCache;
|
import org.thoughtcrime.securesms.util.LRUCache;
|
||||||
|
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
||||||
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
public class RecipientProvider {
|
public class RecipientProvider {
|
||||||
|
|
||||||
private static final Map<String,Recipient> recipientCache = Collections.synchronizedMap(new LRUCache<String,Recipient>(1000));
|
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 = Executors.newSingleThreadExecutor();
|
||||||
|
private static final ExecutorService asyncRecipientResolver = Util.newSingleThreadedLifoExecutor();
|
||||||
|
|
||||||
private static final String[] CALLER_ID_PROJECTION = new String[] {
|
private static final String[] CALLER_ID_PROJECTION = new String[] {
|
||||||
PhoneLookup.DISPLAY_NAME,
|
PhoneLookup.DISPLAY_NAME,
|
||||||
@ -70,70 +75,43 @@ public class RecipientProvider {
|
|||||||
private Recipient getAsynchronousRecipient(final Context context, final String number) {
|
private Recipient getAsynchronousRecipient(final Context context, final String number) {
|
||||||
Log.w("RecipientProvider", "Cache miss [ASYNC]!");
|
Log.w("RecipientProvider", "Cache miss [ASYNC]!");
|
||||||
|
|
||||||
Recipient recipient = new Recipient(null, number, null, ContactPhotoFactory.getDefaultContactPhoto(context));
|
// 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);
|
|
||||||
// recipientCache.put(number, recipient);
|
// 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;
|
// 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));
|
//// 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;
|
package org.thoughtcrime.securesms.util;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class Util {
|
public class Util {
|
||||||
|
|
||||||
public static byte[] combine(byte[] one, byte[] two) {
|
public static byte[] combine(byte[] one, byte[] two) {
|
||||||
@ -62,6 +66,10 @@ public class Util {
|
|||||||
return splitString;
|
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) {
|
// public static Bitmap loadScaledBitmap(InputStream src, int targetWidth, int targetHeight) {
|
||||||
// return BitmapFactory.decodeStream(src);
|
// return BitmapFactory.decodeStream(src);
|
||||||
//// BitmapFactory.Options options = new BitmapFactory.Options();
|
//// BitmapFactory.Options options = new BitmapFactory.Options();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user