Improve EmailAsyncTask

Added 6 methods:
- execute{Parallel,Serial}
- cancelPreviousAndExecute{Parallel,Serial}
- runAsyncParallel{Parallel,Serial} (replacement for Utility.runAsync)

Bug 4083415

Change-Id: I5ca33000e52fc5265ccc84a6e5acb0d3359d0eb4
This commit is contained in:
Makoto Onuki 2011-03-21 14:08:57 -07:00
parent ad93ba9f1c
commit d72f7bdf11
9 changed files with 237 additions and 109 deletions

View File

@ -18,14 +18,16 @@ package com.android.emailcommon.utility;
import android.os.AsyncTask;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
/**
* {@link AsyncTask} substitution for the email app.
*
* Modeled after {@link AsyncTask}; the basic usage is the same, with extra features:
* - Bulk cancellation of multiple tasks. This is mainly used by UI to cancell pending tasks
* - Bulk cancellation of multiple tasks. This is mainly used by UI to cancel pending tasks
* in onDestroy() or similar places.
* - More features to come...
*
@ -33,6 +35,9 @@ import java.util.concurrent.ExecutionException;
* {@link AsyncTask#onProgressUpdate}. Add these when necessary.
*/
public abstract class EmailAsyncTask<Params, Progress, Result> {
private static final Executor SERIAL_EXECUTOR = AsyncTask.SERIAL_EXECUTOR;
private static final Executor PARALLEL_EXECUTOR = AsyncTask.THREAD_POOL_EXECUTOR;
/**
* Tracks {@link EmailAsyncTask}.
*
@ -66,9 +71,34 @@ public abstract class EmailAsyncTask<Params, Progress, Result> {
}
}
/**
* Cancel all instances of the same class as {@code current} other than
* {@code current} itself.
*/
/* package */ void cancelOthers(EmailAsyncTask<?, ?, ?> current) {
final Class<?> clazz = current.getClass();
synchronized (mTasks) {
final ArrayList<EmailAsyncTask<?, ?, ?>> toRemove =
new ArrayList<EmailAsyncTask<?, ?, ?>>();
for (EmailAsyncTask<?, ?, ?> task : mTasks) {
if ((task != current) && task.getClass().equals(clazz)) {
task.cancel(true);
toRemove.add(task);
}
}
for (EmailAsyncTask<?, ?, ?> task : toRemove) {
mTasks.remove(task);
}
}
}
/* package */ int getTaskCountForTest() {
return mTasks.size();
}
/* package */ boolean containsTaskForTest(EmailAsyncTask<?, ?, ?> task) {
return mTasks.contains(task);
}
}
private final Tracker mTracker;
@ -109,46 +139,127 @@ public abstract class EmailAsyncTask<Params, Progress, Result> {
mInnerTask = new InnerTask<Params, Progress, Result>(this);
}
/* package */ void unregisterSelf() {
/* package */ final void unregisterSelf() {
if (mTracker != null) {
mTracker.remove(this);
}
}
/** @see AsyncTask#doInBackground */
protected abstract Result doInBackground(Params... params);
/** @see AsyncTask#cancel(boolean) */
public final boolean cancel(boolean mayInterruptIfRunning) {
return mInnerTask.cancel(mayInterruptIfRunning);
}
/** @see AsyncTask#onCancelled */
protected void onCancelled(Result result) {
}
/** @see AsyncTask#onPostExecute */
protected void onPostExecute(Result result) {
}
public final EmailAsyncTask<Params, Progress, Result> execute(Params... params) {
mInnerTask.execute(params);
/**
* execute on {@link #PARALLEL_EXECUTOR}
*
* @see AsyncTask#execute
*/
public final EmailAsyncTask<Params, Progress, Result> executeParallel(Params... params) {
return executeInternal(PARALLEL_EXECUTOR, false, params);
}
/**
* execute on {@link #SERIAL_EXECUTOR}
*
* @see AsyncTask#execute
*/
public final EmailAsyncTask<Params, Progress, Result> executeSerial(Params... params) {
return executeInternal(SERIAL_EXECUTOR, false, params);
}
/**
* Cancel all previously created instances of the same class tracked by the same
* {@link Tracker}, and then {@link #executeParallel}.
*/
public final EmailAsyncTask<Params, Progress, Result> cancelPreviousAndExecuteParallel(
Params... params) {
return executeInternal(PARALLEL_EXECUTOR, true, params);
}
/**
* Cancel all previously created instances of the same class tracked by the same
* {@link Tracker}, and then {@link #executeSerial}.
*/
public final EmailAsyncTask<Params, Progress, Result> cancelPreviousAndExecuteSerial(
Params... params) {
return executeInternal(SERIAL_EXECUTOR, true, params);
}
private final EmailAsyncTask<Params, Progress, Result> executeInternal(Executor executor,
boolean cancelPrevious, Params... params) {
if (cancelPrevious) {
if (mTracker == null) {
throw new IllegalStateException();
} else {
mTracker.cancelOthers(this);
}
}
mInnerTask.executeOnExecutor(executor, params);
return this;
}
public final Result get() throws InterruptedException, ExecutionException {
return mInnerTask.get();
/**
* Runs a {@link Runnable} in a bg thread, using {@link #PARALLEL_EXECUTOR}.
*/
public static EmailAsyncTask<Void, Void, Void> runAsyncParallel(Runnable runnable) {
return runAsyncInternal(PARALLEL_EXECUTOR, runnable);
}
/**
* Runs a {@link Runnable} in a bg thread, using {@link #SERIAL_EXECUTOR}.
*/
public static EmailAsyncTask<Void, Void, Void> runAsyncSerial(Runnable runnable) {
return runAsyncInternal(SERIAL_EXECUTOR, runnable);
}
private static EmailAsyncTask<Void, Void, Void> runAsyncInternal(Executor executor,
final Runnable runnable) {
EmailAsyncTask<Void, Void, Void> task = new EmailAsyncTask<Void, Void, Void>(null) {
@Override
protected Void doInBackground(Void... params) {
runnable.run();
return null;
}
};
return task.executeInternal(executor, false, (Void[]) null);
}
/**
* Wait until {@link #doInBackground} finishes.
*
* @see AsyncTask#get
*/
public final void waitForFinish() throws InterruptedException, ExecutionException {
mInnerTask.get();
}
/** @see AsyncTask#isCancelled */
public final boolean isCancelled() {
return mInnerTask.isCancelled();
}
/* package */ Result callDoInBackgroundForTest(Params... params) {
/* package */ final Result callDoInBackgroundForTest(Params... params) {
return mInnerTask.doInBackground(params);
}
/* package */ void callOnCancelledForTest(Result result) {
/* package */ final void callOnCancelledForTest(Result result) {
mInnerTask.onCancelled(result);
}
/* package */ void callOnPostExecuteForTest(Result result) {
/* package */ final void callOnPostExecuteForTest(Result result) {
mInnerTask.onPostExecute(result);
}
}

View File

@ -573,14 +573,18 @@ public class Utility {
* Run {@code r} on a worker thread, returning the AsyncTask
* @return the AsyncTask; this is primarily for use by unit tests, which require the
* result of the task
*
* @deprecated use {@link EmailAsyncTask#runAsyncParallel} or
* {@link EmailAsyncTask#runAsyncSerial}
*/
@Deprecated
public static AsyncTask<Void, Void, Void> runAsync(final Runnable r) {
return new AsyncTask<Void, Void, Void>() {
@Override protected Void doInBackground(Void... params) {
r.run();
return null;
}
}.execute();
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
/**

View File

@ -19,12 +19,11 @@ package com.android.email.activity;
import com.android.email.R;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.EmailContent.Account;
import com.android.emailcommon.utility.Utility;
import com.android.emailcommon.utility.EmailAsyncTask;
import android.app.ListActivity;
import android.content.Intent;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcelable;
import android.view.View;
@ -43,7 +42,7 @@ import android.widget.SimpleCursorAdapter;
public class AccountShortcutPicker extends ListActivity
implements OnClickListener, OnItemClickListener {
private AccountTask mAccountTask;
private final EmailAsyncTask.Tracker mTaskTracker = new EmailAsyncTask.Tracker();
/**
* Support for list adapter
@ -74,16 +73,14 @@ public class AccountShortcutPicker extends ListActivity
listView.setOnItemClickListener(this);
listView.setItemsCanFocus(false);
mAccountTask = new AccountTask();
mAccountTask.execute();
new AccountTask().executeParallel();
}
@Override
public void onDestroy() {
super.onDestroy();
// Cleanup running async task (if any)
Utility.cancelTaskInterrupt(mAccountTask);
mAccountTask = null;
mTaskTracker.cancellAllInterrupt();
// Cleanup accounts cursor (if any)
SimpleCursorAdapter adapter = (SimpleCursorAdapter) getListAdapter();
if (adapter != null) {
@ -114,7 +111,10 @@ public class AccountShortcutPicker extends ListActivity
/**
* Load the accounts and create the adapter.
*/
private class AccountTask extends AsyncTask<Void, Void, Cursor> {
private class AccountTask extends EmailAsyncTask<Void, Void, Cursor> {
public AccountTask() {
super(mTaskTracker);
}
@Override
protected Cursor doInBackground(Void... params) {

View File

@ -34,6 +34,7 @@ import com.android.emailcommon.provider.EmailContent.BodyColumns;
import com.android.emailcommon.provider.EmailContent.Message;
import com.android.emailcommon.provider.EmailContent.MessageColumns;
import com.android.emailcommon.utility.AttachmentUtilities;
import com.android.emailcommon.utility.EmailAsyncTask;
import com.android.emailcommon.utility.Utility;
import android.app.ActionBar;
@ -48,7 +49,6 @@ import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcelable;
import android.provider.OpenableColumns;
@ -157,8 +157,7 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
private Controller mController;
private boolean mDraftNeedsSaving;
private boolean mMessageLoaded;
private AsyncTask<Long, Void, Attachment[]> mLoadAttachmentsTask;
private AsyncTask<Void, Void, Object[]> mLoadMessageTask;
private final EmailAsyncTask.Tracker mTaskTracker = new EmailAsyncTask.Tracker();
private EmailAddressAdapter mAddressAdapterTo;
private EmailAddressAdapter mAddressAdapterCc;
@ -336,7 +335,7 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
// Otherwise, handle the internal cases (Message Composer invoked from within app)
long messageId = draftId != -1 ? draftId : intent.getLongExtra(EXTRA_MESSAGE_ID, -1);
if (messageId != -1) {
mLoadMessageTask = new LoadMessageTask(messageId).execute();
new LoadMessageTask(messageId).executeParallel();
} else {
setAccount(intent);
// Since this is a new message, we don't need to call LoadMessageTask.
@ -394,10 +393,7 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
mQuotedText.destroy();
mQuotedText = null;
Utility.cancelTaskInterrupt(mLoadAttachmentsTask);
mLoadAttachmentsTask = null;
Utility.cancelTaskInterrupt(mLoadMessageTask);
mLoadMessageTask = null;
mTaskTracker.cancellAllInterrupt();
if (mAddressAdapterTo != null) {
mAddressAdapterTo.close();
@ -608,10 +604,11 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
mAddressAdapterBcc = new EmailAddressAdapter(this);
}
private class LoadMessageTask extends AsyncTask<Void, Void, Object[]> {
private class LoadMessageTask extends EmailAsyncTask<Void, Void, Object[]> {
private final long mMessageId;
public LoadMessageTask(long messageId) {
super(mTaskTracker);
mMessageId = messageId;
}
@ -686,7 +683,7 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
} else {
mSource = message;
}
mLoadAttachmentsTask = new AsyncTask<Long, Void, Attachment[]>() {
new EmailAsyncTask<Long, Void, Attachment[]>(mTaskTracker) {
@Override
protected Attachment[] doInBackground(Long... messageIds) {
return Attachment.restoreAttachmentsWithMessageId(MessageCompose.this,
@ -716,7 +713,7 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
addAttachment(attachment, allowDelete);
}
}
}.execute(message.mId);
}.executeParallel(message.mId);
} else if (ACTION_REPLY.equals(mAction) || ACTION_REPLY_ALL.equals(mAction)) {
mSource = message;
} else if (Email.LOGD) {
@ -909,10 +906,11 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
}
}
private class SendOrSaveMessageTask extends AsyncTask<Void, Void, Void> {
private class SendOrSaveMessageTask extends EmailAsyncTask<Void, Void, Void> {
private final boolean mSend;
public SendOrSaveMessageTask(boolean send) {
super(null /* DO NOT cancel in onDestroy */);
if (send && ActivityManager.isUserAMonkey()) {
Log.d(Logging.LOG_TAG, "Inhibiting send while monkey is in charge.");
send = false;
@ -994,9 +992,6 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
sSaveInProgress = false;
sSaveInProgressCondition.notify();
}
if (isCancelled()) {
return;
}
// Don't display the toast if the user is just changing the orientation
if (!mSend && (getChangingConfigurations() & ActivityInfo.CONFIG_ORIENTATION) == 0) {
Toast.makeText(MessageCompose.this, R.string.message_saved_toast,
@ -1020,7 +1015,7 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
synchronized (sSaveInProgressCondition) {
sSaveInProgress = true;
}
new SendOrSaveMessageTask(send).execute();
new SendOrSaveMessageTask(send).executeParallel();
}
private void saveIfNeeded() {
@ -1252,16 +1247,13 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
mAttachments.removeView(attachmentView);
updateAttachmentContainer();
if (attachment.mMessageKey == mDraft.mId && attachment.isSaved()) {
// The following async task for deleting attachments:
// - can be started multiple times in parallel (to delete multiple attachments).
// - need not be interrupted on activity exit, instead should run to completion.
new AsyncTask<Long, Void, Void>() {
final long attachmentId = attachment.mId;
EmailAsyncTask.runAsyncParallel(new Runnable() {
@Override
protected Void doInBackground(Long... attachmentIds) {
mController.deleteAttachment(attachmentIds[0]);
return null;
public void run() {
mController.deleteAttachment(attachmentId);
}
}.execute(attachment.mId);
});
}
setDraftNeedsSaving(true);
}

View File

@ -28,6 +28,7 @@ import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.EmailContent.Account;
import com.android.emailcommon.provider.EmailContent.Mailbox;
import com.android.emailcommon.provider.EmailContent.Message;
import com.android.emailcommon.utility.EmailAsyncTask;
import com.android.emailcommon.utility.Utility;
import com.android.emailcommon.utility.Utility.ListStateSaver;
@ -42,13 +43,11 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@ -160,7 +159,7 @@ public class MessageListFragment extends ListFragment
private Utility.ListStateSaver mSavedListState;
private MessageOpenTask mMessageOpenTask;
private final EmailAsyncTask.Tracker mTaskTracker = new EmailAsyncTask.Tracker();
/**
* Callback interface that owning activities must implement
@ -306,8 +305,7 @@ public class MessageListFragment extends ListFragment
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "MessageListFragment onDestroy");
}
Utility.cancelTaskInterrupt(mMessageOpenTask);
mMessageOpenTask = null;
mTaskTracker.cancellAllInterrupt();
mRefreshManager.unregisterListener(mRefreshListener);
super.onDestroy();
}
@ -637,19 +635,18 @@ public class MessageListFragment extends ListFragment
* @param messageId ID of the msesage to open.
*/
private void onMessageOpen(final long messageMailboxId, final long messageId) {
Utility.cancelTaskInterrupt(mMessageOpenTask);
mMessageOpenTask = new MessageOpenTask(messageMailboxId, messageId);
mMessageOpenTask.execute();
new MessageOpenTask(messageMailboxId, messageId).cancelPreviousAndExecuteParallel();
}
/**
* Task to look up the mailbox type for a message, and kicks the callback.
*/
private class MessageOpenTask extends AsyncTask<Void, Void, Integer> {
private class MessageOpenTask extends EmailAsyncTask<Void, Void, Integer> {
private final long mMessageMailboxId;
private final long mMessageId;
public MessageOpenTask(long messageMailboxId, long messageId) {
super(mTaskTracker);
mMessageMailboxId = messageMailboxId;
mMessageId = messageId;
}

View File

@ -30,6 +30,7 @@ import com.android.emailcommon.Logging;
import com.android.emailcommon.mail.MessagingException;
import com.android.emailcommon.provider.EmailContent.Account;
import com.android.emailcommon.provider.EmailContent.Mailbox;
import com.android.emailcommon.utility.EmailAsyncTask;
import com.android.emailcommon.utility.Utility;
import android.app.ActionBar;
@ -39,7 +40,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
@ -88,7 +88,7 @@ public class MessageListXL extends Activity implements
private final MessageOrderManagerCallback mMessageOrderManagerCallback
= new MessageOrderManagerCallback();
private RefreshTask mRefreshTask;
private final EmailAsyncTask.Tracker mTaskTracker = new EmailAsyncTask.Tracker();
private BannerController mBannerController;
private TextView mErrorMessageView;
@ -264,7 +264,7 @@ public class MessageListXL extends Activity implements
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) Log.d(Logging.LOG_TAG, "MessageListXL onDestroy");
mIsCreated = false;
mController.removeResultCallback(mControllerResult);
Utility.cancelTaskInterrupt(mRefreshTask);
mTaskTracker.cancellAllInterrupt();
mRefreshManager.unregisterListener(mMailRefreshManagerListener);
mFragmentManager.onDestroy();
super.onDestroy();
@ -561,7 +561,7 @@ public class MessageListXL extends Activity implements
* Call this when getting a connection error.
*/
private void showErrorMessage(final String rawMessage, final long accountId) {
new AsyncTask<Void, Void, String>() {
new EmailAsyncTask<Void, Void, String>(mTaskTracker) {
@Override
protected String doInBackground(Void... params) {
Account account = Account.restoreAccountWithId(MessageListXL.this, accountId);
@ -570,9 +570,6 @@ public class MessageListXL extends Activity implements
@Override
protected void onPostExecute(String accountName) {
if (!mIsCreated) {
return; // activity destroyed.
}
final String message;
if (TextUtils.isEmpty(accountName)) {
message = rawMessage;
@ -585,8 +582,7 @@ public class MessageListXL extends Activity implements
mLastErrorAccountId = accountId;
}
}
}.execute();
}.executeParallel();
}
/**
@ -776,10 +772,8 @@ public class MessageListXL extends Activity implements
private void onRefresh() {
// Cancel previously running instance if any.
Utility.cancelTaskInterrupt(mRefreshTask);
mRefreshTask = new RefreshTask(this, mFragmentManager.getActualAccountId(),
mFragmentManager.getMailboxId());
mRefreshTask.execute();
new RefreshTask(mTaskTracker, this, mFragmentManager.getActualAccountId(),
mFragmentManager.getMailboxId()).cancelPreviousAndExecuteParallel();
}
/**
@ -795,7 +789,7 @@ public class MessageListXL extends Activity implements
* {@link #INBOX_AUTO_REFRESH_MIN_INTERVAL}.
* </ul>
*/
/* package */ static class RefreshTask extends AsyncTask<Void, Void, Boolean> {
/* package */ static class RefreshTask extends EmailAsyncTask<Void, Void, Boolean> {
private final Clock mClock;
private final Context mContext;
private final long mAccountId;
@ -803,13 +797,15 @@ public class MessageListXL extends Activity implements
private final RefreshManager mRefreshManager;
/* package */ long mInboxId;
public RefreshTask(Context context, long accountId, long mailboxId) {
this(context, accountId, mailboxId, Clock.INSTANCE,
public RefreshTask(EmailAsyncTask.Tracker tracker, Context context, long accountId,
long mailboxId) {
this(tracker, context, accountId, mailboxId, Clock.INSTANCE,
RefreshManager.getInstance(context));
}
/* package */ RefreshTask(Context context, long accountId, long mailboxId, Clock clock,
RefreshManager refreshManager) {
/* package */ RefreshTask(EmailAsyncTask.Tracker tracker, Context context, long accountId,
long mailboxId, Clock clock, RefreshManager refreshManager) {
super(tracker);
mClock = clock;
mContext = context;
mRefreshManager = refreshManager;

View File

@ -56,7 +56,6 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
@ -137,11 +136,6 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
private long mMessageId = -1;
private Message mMessage;
private LoadMessageTask mLoadMessageTask;
private ReloadMessageTask mReloadMessageTask;
private LoadBodyTask mLoadBodyTask;
private LoadAttachmentsTask mLoadAttachmentsTask;
private Controller mController;
private ControllerResultUiThreadWrapper<ControllerResults> mControllerCallback;
@ -206,8 +200,7 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
private boolean mRestoredPictureLoaded;
private final EmailAsyncTask.Tracker mUpdatePreviewIconTaskTracker
= new EmailAsyncTask.Tracker();
private final EmailAsyncTask.Tracker mTaskTracker = new EmailAsyncTask.Tracker();
/**
* Zoom scales for webview. Values correspond to {@link Preferences#TEXT_ZOOM_TINY}..
@ -427,15 +420,7 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
private void cancelAllTasks() {
mMessageObserver.unregister();
mUpdatePreviewIconTaskTracker.cancellAllInterrupt();
Utility.cancelTaskInterrupt(mLoadMessageTask);
mLoadMessageTask = null;
Utility.cancelTaskInterrupt(mReloadMessageTask);
mReloadMessageTask = null;
Utility.cancelTaskInterrupt(mLoadBodyTask);
mLoadBodyTask = null;
Utility.cancelTaskInterrupt(mLoadAttachmentsTask);
mLoadAttachmentsTask = null;
mTaskTracker.cancellAllInterrupt();
}
/**
@ -483,8 +468,7 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
mLoadWhenResumed = false;
cancelAllTasks();
resetView();
mLoadMessageTask = new LoadMessageTask(true);
mLoadMessageTask.execute();
new LoadMessageTask(true).executeParallel();
}
/**
@ -816,7 +800,7 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
// assume the download won't start right away, and we make the cancel button visible
attachment.cancelButton.setVisibility(View.GONE);
// Create the timed task that will change the button state
new AsyncTask<Void, Void, Void>() {
new EmailAsyncTask<Void, Void, Void>(mTaskTracker) {
@Override
protected Void doInBackground(Void... params) {
try {
@ -831,7 +815,7 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
attachment.cancelButton.setVisibility(View.VISIBLE);
}
}
}.execute();
}.executeParallel();
} else {
attachment.cancelButton.setVisibility(View.VISIBLE);
}
@ -966,7 +950,7 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
/**
* Async task for loading a single message outside of the UI thread
*/
private class LoadMessageTask extends AsyncTask<Void, Void, Message> {
private class LoadMessageTask extends EmailAsyncTask<Void, Void, Message> {
private final boolean mOkToFetch;
private int mMailboxType;
@ -975,6 +959,7 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
* Special constructor to cache some local info
*/
public LoadMessageTask(boolean okToFetch) {
super(mTaskTracker);
mOkToFetch = okToFetch;
}
@ -1015,7 +1000,11 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
/**
* Kicked by {@link MessageObserver}. Reload the message and update the views.
*/
private class ReloadMessageTask extends AsyncTask<Void, Void, Message> {
private class ReloadMessageTask extends EmailAsyncTask<Void, Void, Message> {
public ReloadMessageTask() {
super(mTaskTracker);
}
@Override
protected Message doInBackground(Void... params) {
if (!isMessageSpecified()) { // just in case
@ -1060,7 +1049,7 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
/**
* Async task for loading a single message body outside of the UI thread
*/
private class LoadBodyTask extends AsyncTask<Void, Void, String[]> {
private class LoadBodyTask extends EmailAsyncTask<Void, Void, String[]> {
private long mId;
private boolean mErrorLoadingMessageBody;
@ -1069,6 +1058,7 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
* Special constructor to cache some local info
*/
public LoadBodyTask(long messageId) {
super(mTaskTracker);
mId = messageId;
}
@ -1112,7 +1102,11 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
* this implementation is incomplete, as it will fail to refresh properly if the message is
* partially loaded at this time.
*/
private class LoadAttachmentsTask extends AsyncTask<Long, Void, Attachment[]> {
private class LoadAttachmentsTask extends EmailAsyncTask<Long, Void, Attachment[]> {
public LoadAttachmentsTask() {
super(mTaskTracker);
}
@Override
protected Attachment[] doInBackground(Long... messageIds) {
return Attachment.restoreAttachmentsWithMessageId(mContext, messageIds[0]);
@ -1419,8 +1413,7 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
} else {
mControllerCallback.getWrappee().setWaitForLoadMessageId(-1);
// Ask for body
mLoadBodyTask = new LoadBodyTask(message.mId);
mLoadBodyTask.execute();
new LoadBodyTask(message.mId).executeParallel();
}
}
@ -1560,8 +1553,7 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
setMessageHtml(text);
// Ask for attachments after body
mLoadAttachmentsTask = new LoadAttachmentsTask();
mLoadAttachmentsTask.execute(mMessage.mId);
new LoadAttachmentsTask().executeParallel(mMessage.mId);
mIsMessageLoadedForTest = true;
}
@ -1626,8 +1618,7 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
// reload UI and reload everything else too
// pass false to LoadMessageTask to prevent looping here
cancelAllTasks();
mLoadMessageTask = new LoadMessageTask(false);
mLoadMessageTask.execute();
new LoadMessageTask(false).executeParallel();
break;
default:
// do nothing - we don't have a progress bar at this time
@ -1748,14 +1739,12 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
if (!isMessageSpecified()) {
return;
}
Utility.cancelTaskInterrupt(mReloadMessageTask);
mReloadMessageTask = new ReloadMessageTask();
mReloadMessageTask.execute();
new ReloadMessageTask().cancelPreviousAndExecuteParallel();
}
}
private void updatePreviewIcon(MessageViewAttachmentInfo attachmentInfo) {
new UpdatePreviewIconTask(attachmentInfo).execute();
new UpdatePreviewIconTask(attachmentInfo).executeParallel();
}
private class UpdatePreviewIconTask extends EmailAsyncTask<Void, Void, Bitmap> {
@ -1764,7 +1753,7 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
private final MessageViewAttachmentInfo mAttachmentInfo;
public UpdatePreviewIconTask(MessageViewAttachmentInfo attachmentInfo) {
super(mUpdatePreviewIconTaskTracker);
super(mTaskTracker);
mContext = getActivity();
mAttachmentInfo = attachmentInfo;
}

View File

@ -57,8 +57,8 @@ public class MessageListXLRefreshTaskTest extends AndroidTestCase {
final long ACCOUNT_ID = 5;
final long MAILBOX_ID = 10;
MessageListXL.RefreshTask task = new MessageListXL.RefreshTask(getContext(), ACCOUNT_ID,
MAILBOX_ID, mClock, mRefreshManager);
MessageListXL.RefreshTask task = new MessageListXL.RefreshTask(null, getContext(),
ACCOUNT_ID, MAILBOX_ID, mClock, mRefreshManager);
mRefreshManager.mExpectedAccountId = ACCOUNT_ID;
@ -100,8 +100,8 @@ public class MessageListXLRefreshTaskTest extends AndroidTestCase {
final long ACCOUNT_ID = 5;
final long MAILBOX_ID = 10;
MessageListXL.RefreshTask task = new MessageListXL.RefreshTask(getContext(), ACCOUNT_ID,
MAILBOX_ID, mClock, mRefreshManager);
MessageListXL.RefreshTask task = new MessageListXL.RefreshTask(null, getContext(),
ACCOUNT_ID, MAILBOX_ID, mClock, mRefreshManager);
mRefreshManager.mExpectedAccountId = ACCOUNT_ID;

View File

@ -16,6 +16,8 @@
package com.android.emailcommon.utility;
import com.android.emailcommon.utility.EmailAsyncTask.Tracker;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
@ -82,6 +84,37 @@ public class EmailAsyncTaskTests extends AndroidTestCase {
task1.unregisterSelf();
}
/**
* Test for {@link EmailAsyncTask.Tracker#cancelOthers}
*/
public void testCancellOthers() {
final EmailAsyncTask.Tracker tracker = new EmailAsyncTask.Tracker();
final MyTask task1 = new MyTask(tracker);
final MyTask task2 = new MyTask(tracker);
final MyTask task3 = new MyTask(tracker);
final MyTask sub1 = new MyTaskSubClass(tracker);
final MyTask sub2 = new MyTaskSubClass(tracker);
final MyTask sub3 = new MyTaskSubClass(tracker);
// All should be in the tracker.
assertEquals(6, tracker.getTaskCountForTest());
// This should remove task1, task2, but not task3 itself.
tracker.cancelOthers(task3);
assertEquals(4, tracker.getTaskCountForTest());
assertTrue(tracker.containsTaskForTest(task3));
// Same for sub1.
tracker.cancelOthers(sub1);
assertEquals(2, tracker.getTaskCountForTest());
assertTrue(tracker.containsTaskForTest(task3));
assertTrue(tracker.containsTaskForTest(sub1));
}
private static class MyTask extends EmailAsyncTask<String, String, String> {
public String[] mDoInBackgroundArg;
public String mDoInBackgroundResult;
@ -108,4 +141,10 @@ public class EmailAsyncTaskTests extends AndroidTestCase {
mOnPostExecuteArg = result;
}
}
private static class MyTaskSubClass extends MyTask {
public MyTaskSubClass(Tracker tracker) {
super(tracker);
}
}
}