svn merge -x -w -c 760 ../issue4-1.X/ .

Improve reliability of message viewing and composing while still using
MessagingController worker queues

svn merge -x -w -c 761 ../issue4-1.X/ .

Put loading a message from the LocalStore into a ThreadPool executor,
like was done previously in MessageView.  Remote loading still goes
through the work queue.
This commit is contained in:
Daniel Applebaum 2009-09-17 03:43:02 +00:00
parent 5d5c65bee3
commit 08cd19e5a8
2 changed files with 46 additions and 30 deletions

View file

@ -15,6 +15,8 @@ import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@ -106,6 +108,8 @@ public class MessagingController implements Runnable {
private ConcurrentHashMap<String, AtomicInteger> sendCount = new ConcurrentHashMap<String, AtomicInteger>();
private final ExecutorService threadPool = Executors.newFixedThreadPool(3);
public enum SORT_TYPE {
SORT_DATE(R.string.sort_earliest_first, R.string.sort_latest_first, false),
SORT_SUBJECT(R.string.sort_subject_alpha, R.string.sort_subject_re_alpha, true),
@ -287,10 +291,10 @@ public class MessagingController implements Runnable {
if (command != null) {
commandDescription = command.description;
Log.d(Email.LOG_TAG, "Running background command '" + command.description + "'");
Log.i(Email.LOG_TAG, "Running background command '" + command.description + "'");
mBusy = true;
command.runnable.run();
Log.d(Email.LOG_TAG, "Background command '" + command.description + "' completed");
Log.i(Email.LOG_TAG, "Background command '" + command.description + "' completed");
for (MessagingListener l : getListeners()) {
l.controllerCommandCompleted(mCommands.size() > 0);
}
@ -307,25 +311,20 @@ public class MessagingController implements Runnable {
}
private void put(String description, MessagingListener listener, Runnable runnable) {
try {
Command command = new Command();
command.listener = listener;
command.runnable = runnable;
command.description = description;
mCommands.put(command);
putCommand(mCommands, description, listener, runnable);
}
catch (InterruptedException ie) {
throw new Error(ie);
}
}
private void putBackground(String description, MessagingListener listener, Runnable runnable) {
putCommand(backCommands, description, listener, runnable);
}
private void putCommand(BlockingQueue<Command> queue, String description, MessagingListener listener, Runnable runnable) {
try {
Command command = new Command();
command.listener = listener;
command.runnable = runnable;
command.description = description;
backCommands.put(command);
queue.put(command);
}
catch (InterruptedException ie) {
throw new Error(ie);
@ -1797,14 +1796,14 @@ public class MessagingController implements Runnable {
markMessageRead(account, localFolder, message, true);
}
if (listener != null)
if (listener != null && !getListeners().contains(listener))
{
listener.loadMessageForViewBodyAvailable(account, folder, uid, message);
}
for (MessagingListener l : getListeners()) {
l.loadMessageForViewBodyAvailable(account, folder, uid, message);
}
if (listener != null)
if (listener != null && !getListeners().contains(listener))
{
listener.loadMessageForViewFinished(account, folder, uid, message);
}
@ -1816,6 +1815,10 @@ public class MessagingController implements Runnable {
for (MessagingListener l : getListeners()) {
l.loadMessageForViewFailed(account, folder, uid, e.getMessage());
}
if (listener != null && !getListeners().contains(listener))
{
listener.loadMessageForViewFailed(account, folder, uid, e.getMessage());
}
addErrorMessage(account, e);
}
@ -1843,10 +1846,17 @@ public class MessagingController implements Runnable {
}
public void loadMessageForView(final Account account, final String folder, final String uid,
MessagingListener listener) {
final MessagingListener listener) {
for (MessagingListener l : getListeners()) {
l.loadMessageForViewStarted(account, folder, uid);
}
if (listener != null && !getListeners().contains(listener))
{
listener.loadMessageForViewStarted(account, folder, uid);
}
threadPool.execute(new Runnable() {
public void run() {
try {
Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication);
LocalFolder localFolder = (LocalFolder) localStore.getFolder(folder);
@ -1857,7 +1867,7 @@ public class MessagingController implements Runnable {
for (MessagingListener l : getListeners()) {
l.loadMessageForViewHeadersAvailable(account, folder, uid, message);
}
if (listener != null)
if (listener != null && !getListeners().contains(listener))
{
listener.loadMessageForViewHeadersAvailable(account, folder, uid, message);
}
@ -1874,7 +1884,7 @@ public class MessagingController implements Runnable {
localFolder.fetch(new Message[] {
message
}, fp, null);
localFolder.close(false);
if (!message.isSet(Flag.SEEN)) {
markMessageRead(account, localFolder, message, true);
}
@ -1882,7 +1892,7 @@ public class MessagingController implements Runnable {
for (MessagingListener l : getListeners()) {
l.loadMessageForViewBodyAvailable(account, folder, uid, message);
}
if (listener != null)
if (listener != null && !getListeners().contains(listener))
{
listener.loadMessageForViewBodyAvailable(account, folder, uid, message);
}
@ -1890,19 +1900,25 @@ public class MessagingController implements Runnable {
for (MessagingListener l : getListeners()) {
l.loadMessageForViewFinished(account, folder, uid, message);
}
if (listener != null)
if (listener != null && !getListeners().contains(listener))
{
listener.loadMessageForViewFinished(account, folder, uid, message);
}
localFolder.close(false);
}
catch (Exception e) {
for (MessagingListener l : getListeners()) {
l.loadMessageForViewFailed(account, folder, uid, e.getMessage());
}
if (listener != null && !getListeners().contains(listener))
{
listener.loadMessageForViewFailed(account, folder, uid, e.getMessage());
}
addErrorMessage(account, e);
}
}
});
}
// public void loadMessageForViewSynchronous(final Account account, final String folder, final String uid,

View file

@ -500,14 +500,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
updateFrom();
updateSignature();
Log.d(Email.LOG_TAG, "action = " + action + ", mAccount = " + mAccount + ", mFolder = " + mFolder + ", mSourceMessageUid = " + mSourceMessageUid);
if ((ACTION_REPLY.equals(action) || ACTION_REPLY_ALL.equals(action)) && mAccount != null && mFolder != null && mSourceMessageUid != null) {
Log.d(Email.LOG_TAG, "Setting message ANSWERED flag to true");
// TODO: Really, we should wait until we send the message, but that would require saving the original
// message info along with a Draft copy, in case it is left in Drafts for a while before being sent
MessagingController.getInstance(getApplication()).setMessageFlag(mAccount, mFolder, mSourceMessageUid, Flag.ANSWERED, true);
}
if (ACTION_REPLY.equals(action) || ACTION_REPLY_ALL.equals(action) || ACTION_FORWARD.equals(action) || ACTION_EDIT_DRAFT.equals(action)) {
/*
* If we need to load the message we add ourself as a message listener here
@ -527,6 +519,14 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
addAddress(mBccView, new Address(mAccount.getAlwaysBcc(), ""));
}
Log.d(Email.LOG_TAG, "action = " + action + ", mAccount = " + mAccount + ", mFolder = " + mFolder + ", mSourceMessageUid = " + mSourceMessageUid);
if ((ACTION_REPLY.equals(action) || ACTION_REPLY_ALL.equals(action)) && mAccount != null && mFolder != null && mSourceMessageUid != null) {
Log.d(Email.LOG_TAG, "Setting message ANSWERED flag to true");
// TODO: Really, we should wait until we send the message, but that would require saving the original
// message info along with a Draft copy, in case it is left in Drafts for a while before being sent
MessagingController.getInstance(getApplication()).setMessageFlag(mAccount, mFolder, mSourceMessageUid, Flag.ANSWERED, true);
}
updateTitle();
}