From f1d413ce77ab9c656ca391e8553b64535b2f9572 Mon Sep 17 00:00:00 2001 From: Fiouz Date: Sun, 3 Oct 2010 10:56:16 +0000 Subject: [PATCH] Optimization: extracted populate() outside MessageInfoHolder in order to properly cache DateFormat (avoid useless DateFormat costly lookup at each population) --- .../fsck/k9/activity/MessageInfoHolder.java | 106 --------------- src/com/fsck/k9/activity/MessageList.java | 59 ++++---- src/com/fsck/k9/helper/MessageHelper.java | 126 ++++++++++++++++++ src/com/fsck/k9/provider/MessageProvider.java | 32 ++++- 4 files changed, 188 insertions(+), 135 deletions(-) create mode 100644 src/com/fsck/k9/helper/MessageHelper.java diff --git a/src/com/fsck/k9/activity/MessageInfoHolder.java b/src/com/fsck/k9/activity/MessageInfoHolder.java index 33634f52e..fe36a2f66 100644 --- a/src/com/fsck/k9/activity/MessageInfoHolder.java +++ b/src/com/fsck/k9/activity/MessageInfoHolder.java @@ -1,22 +1,7 @@ package com.fsck.k9.activity; import java.util.Date; -import android.content.Context; -import android.text.SpannableStringBuilder; -import android.util.Config; -import android.util.Log; - -import com.fsck.k9.Account; -import com.fsck.k9.K9; -import com.fsck.k9.R; -import com.fsck.k9.helper.Contacts; -import com.fsck.k9.helper.Utility; -import com.fsck.k9.mail.Address; -import com.fsck.k9.mail.Flag; import com.fsck.k9.mail.Message; -import com.fsck.k9.mail.MessagingException; -import com.fsck.k9.mail.Message.RecipientType; -import com.fsck.k9.mail.store.LocalStore.LocalMessage; public class MessageInfoHolder { @@ -49,97 +34,6 @@ public class MessageInfoHolder this.selected = false; } - public MessageInfoHolder(Context context, Message m) - { - this(); - - Account account = m.getFolder().getAccount(); - populate(context, m, new FolderInfoHolder(context, m.getFolder(), m.getFolder().getAccount()), account); - } - - public MessageInfoHolder(Context context, Message m, FolderInfoHolder folder, Account account) - { - this(); - - populate(context, m, folder, account); - } - - public void populate(Context context, Message m, FolderInfoHolder folder, Account account) - { - final Contacts contactHelper = Contacts.getInstance(context); - try - { - LocalMessage message = (LocalMessage) m; - Date date = message.getSentDate(); - this.compareDate = message.getSentDate(); - if (this.compareDate == null) - { - this.compareDate = message.getInternalDate(); - } - - this.folder = folder; - - if (Utility.isDateToday(date)) - { - this.date = android.text.format.DateFormat.getTimeFormat(context).format(date); - } - else - { - this.date = DateFormatter.getDateFormat(context).format(date); - } - - this.hasAttachments = message.getAttachmentCount() > 0; - - this.read = message.isSet(Flag.SEEN); - this.answered = message.isSet(Flag.ANSWERED); - this.flagged = message.isSet(Flag.FLAGGED); - this.downloaded = message.isSet(Flag.X_DOWNLOADED_FULL); - this.partially_downloaded = message.isSet(Flag.X_DOWNLOADED_PARTIAL); - - Address[] addrs = message.getFrom(); - - if (addrs.length > 0 && account.isAnIdentity(addrs[0])) - { - CharSequence to = Address.toFriendly(message .getRecipients(RecipientType.TO), contactHelper); - this.compareCounterparty = to.toString(); - this.sender = new SpannableStringBuilder(context.getString(R.string.message_list_to_fmt)).append(to); - } - else - { - this.sender = Address.toFriendly(addrs, contactHelper); - this.compareCounterparty = this.sender.toString(); - } - - if (addrs.length > 0) - { - this.senderAddress = addrs[0].getAddress(); - } - else - { - // a reasonable fallback "whomever we were corresponding with - this.senderAddress = this.compareCounterparty; - } - - this.subject = message.getSubject(); - - this.uid = message.getUid(); - this.message = m; - this.preview = message.getPreview(); - - this.fullDate = DateFormatter.getDateFormat(context).format(date)+" "+android.text.format.DateFormat.getTimeFormat(context).format(date); - this.account = account.getDescription(); - this.uri = "email://messages/"+account.getAccountNumber()+"/"+m.getFolder().getName()+"/"+m.getUid(); - - } - catch (MessagingException me) - { - if (Config.LOGV) - { - Log.v(K9.LOG_TAG, "Unable to load message info", me); - } - } - } - @Override public boolean equals(Object o) { diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java index e767a79fc..5c4c693dd 100644 --- a/src/com/fsck/k9/activity/MessageList.java +++ b/src/com/fsck/k9/activity/MessageList.java @@ -60,6 +60,7 @@ import com.fsck.k9.activity.setup.Prefs; import com.fsck.k9.controller.MessagingController; import com.fsck.k9.controller.MessagingListener; import com.fsck.k9.controller.MessagingController.SORT_TYPE; +import com.fsck.k9.helper.MessageHelper; import com.fsck.k9.helper.Utility; import com.fsck.k9.mail.Flag; import com.fsck.k9.mail.Folder; @@ -317,6 +318,8 @@ public class MessageList private Context context = null; + /* package visibility for faster inner class access */ MessageHelper mMessageHelper = MessageHelper.getInstance(this); + class MessageListHandler { public void removeMessage(final List messages) @@ -2262,14 +2265,14 @@ public class MessageList removeMessages(messages); } - private void addOrUpdateMessage(Account account, String folder, Message message, boolean verifyAgainstSearch) + private void addOrUpdateMessage(Account account, String folderName, Message message, boolean verifyAgainstSearch) { List messages = new ArrayList(); messages.add(message); - addOrUpdateMessages(account, folder, messages, verifyAgainstSearch); + addOrUpdateMessages(account, folderName, messages, verifyAgainstSearch); } - private void addOrUpdateMessages(final Account account, final String folder, final List providedMessages, final boolean verifyAgainstSearch) + private void addOrUpdateMessages(final Account account, final String folderName, final List providedMessages, final boolean verifyAgainstSearch) { // we copy the message list because the callback doesn't expect // the callbacks to mutate it. @@ -2284,6 +2287,9 @@ public class MessageList List messagesToRemove = new ArrayList(); List messagesToSearch = new ArrayList(); + // cache field into local variable for faster access for JVM without JIT + final MessageHelper messageHelper = mMessageHelper; + for (Message message : messages) { MessageInfoHolder m = getMessage(message); @@ -2294,33 +2300,40 @@ public class MessageList messagesToRemove.add(m); } } - else if (m == null) + else { - if (updateForMe(account, folder)) + final Folder messageFolder = message.getFolder(); + final Account messageAccount = messageFolder.getAccount(); + if (m == null) { - m = new MessageInfoHolder(context, message); - messagesToAdd.add(m); - } - else - { - if (mQueryString != null) + if (updateForMe(account, folderName)) { - if (verifyAgainstSearch) + m = new MessageInfoHolder(); + messageHelper.populate(m, message, new FolderInfoHolder(MessageList.this, messageFolder, messageAccount), messageAccount); + messagesToAdd.add(m); + } + else + { + if (mQueryString != null) { - messagesToSearch.add(message); - } - else - { - m = new MessageInfoHolder(context, message); - messagesToAdd.add(m); + if (verifyAgainstSearch) + { + messagesToSearch.add(message); + } + else + { + m = new MessageInfoHolder(); + messageHelper.populate(m, message, new FolderInfoHolder(MessageList.this, messageFolder, messageAccount), messageAccount); + messagesToAdd.add(m); + } } } } - } - else - { - m.populate(context, message, new FolderInfoHolder(context, message.getFolder(), account), account); - needsSort = true; + else + { + messageHelper.populate(m, message, new FolderInfoHolder(MessageList.this, messageFolder, account), account); + needsSort = true; + } } } diff --git a/src/com/fsck/k9/helper/MessageHelper.java b/src/com/fsck/k9/helper/MessageHelper.java new file mode 100644 index 000000000..b99ca8ec1 --- /dev/null +++ b/src/com/fsck/k9/helper/MessageHelper.java @@ -0,0 +1,126 @@ +package com.fsck.k9.helper; + +import java.text.DateFormat; +import java.util.Date; + +import android.content.Context; +import android.text.SpannableStringBuilder; +import android.util.Log; + +import com.fsck.k9.Account; +import com.fsck.k9.K9; +import com.fsck.k9.R; +import com.fsck.k9.activity.DateFormatter; +import com.fsck.k9.activity.FolderInfoHolder; +import com.fsck.k9.activity.MessageInfoHolder; +import com.fsck.k9.mail.Address; +import com.fsck.k9.mail.Flag; +import com.fsck.k9.mail.Message; +import com.fsck.k9.mail.MessagingException; +import com.fsck.k9.mail.Message.RecipientType; +import com.fsck.k9.mail.store.LocalStore.LocalMessage; + +public class MessageHelper +{ + + private static MessageHelper sInstance; + + public synchronized static MessageHelper getInstance(final Context context) + { + if (sInstance == null) + { + sInstance = new MessageHelper(context); + } + return sInstance; + } + + private Context mContext; + + private DateFormat mTodayDateFormat; + + private DateFormat mDateFormat; + + private DateFormat mTimeFormat; + + private MessageHelper(final Context context) + { + mContext = context; + mDateFormat = DateFormatter.getDateFormat(mContext); + mTimeFormat = android.text.format.DateFormat.getTimeFormat(mContext); + mTodayDateFormat = android.text.format.DateFormat.getTimeFormat(mContext); + } + + public void populate(final MessageInfoHolder target, final Message m, + final FolderInfoHolder folder, final Account account) + { + final Contacts contactHelper = Contacts.getInstance(mContext); + try + { + LocalMessage message = (LocalMessage) m; + Date date = message.getSentDate(); + target.compareDate = message.getSentDate(); + if (target.compareDate == null) + { + target.compareDate = message.getInternalDate(); + } + + target.folder = folder; + + if (Utility.isDateToday(date)) + { + target.date = mTodayDateFormat.format(date); + } + else + { + target.date = mDateFormat.format(date); + } + + target.hasAttachments = message.getAttachmentCount() > 0; + + target.read = message.isSet(Flag.SEEN); + target.answered = message.isSet(Flag.ANSWERED); + target.flagged = message.isSet(Flag.FLAGGED); + target.downloaded = message.isSet(Flag.X_DOWNLOADED_FULL); + target.partially_downloaded = message.isSet(Flag.X_DOWNLOADED_PARTIAL); + + Address[] addrs = message.getFrom(); + + if (addrs.length > 0 && account.isAnIdentity(addrs[0])) + { + CharSequence to = Address.toFriendly(message .getRecipients(RecipientType.TO), contactHelper); + target.compareCounterparty = to.toString(); + target.sender = new SpannableStringBuilder(mContext.getString(R.string.message_list_to_fmt)).append(to); + } + else + { + target.sender = Address.toFriendly(addrs, contactHelper); + target.compareCounterparty = target.sender.toString(); + } + + if (addrs.length > 0) + { + target.senderAddress = addrs[0].getAddress(); + } + else + { + // a reasonable fallback "whomever we were corresponding with + target.senderAddress = target.compareCounterparty; + } + + target.subject = message.getSubject(); + + target.uid = message.getUid(); + target.message = m; + target.preview = message.getPreview(); + + target.fullDate = mDateFormat.format(date) + " " + mTimeFormat.format(date); + target.account = account.getDescription(); + target.uri = "email://messages/" + account.getAccountNumber() + "/" + m.getFolder().getName() + "/" + m.getUid(); + + } + catch (MessagingException me) + { + Log.w(K9.LOG_TAG, "Unable to load message info", me); + } + } +} diff --git a/src/com/fsck/k9/provider/MessageProvider.java b/src/com/fsck/k9/provider/MessageProvider.java index 75e2e4243..eab333e60 100644 --- a/src/com/fsck/k9/provider/MessageProvider.java +++ b/src/com/fsck/k9/provider/MessageProvider.java @@ -8,6 +8,7 @@ import java.util.concurrent.SynchronousQueue; import android.content.ContentProvider; import android.content.ContentValues; +import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.MatrixCursor; @@ -19,10 +20,12 @@ import com.fsck.k9.AccountStats; import com.fsck.k9.K9; import com.fsck.k9.Preferences; import com.fsck.k9.SearchAccount; +import com.fsck.k9.activity.FolderInfoHolder; import com.fsck.k9.activity.MessageInfoHolder; import com.fsck.k9.activity.MessageList; import com.fsck.k9.controller.MessagingController; import com.fsck.k9.controller.MessagingListener; +import com.fsck.k9.helper.MessageHelper; import com.fsck.k9.mail.Folder; import com.fsck.k9.mail.Message; import com.fsck.k9.mail.MessagingException; @@ -229,25 +232,38 @@ public class MessageProvider extends ContentProvider { private final BlockingQueue> queue; - private List holders = new ArrayList(); + private List mHolders = new ArrayList(); /** * @param queue * Never null. The synchronized channel to use * to retrieve {@link MessageInfoHolder}s. */ - public MesssageInfoHolderRetrieverListener(BlockingQueue> queue) + public MesssageInfoHolderRetrieverListener(final BlockingQueue> queue) { this.queue = queue; } @Override - public void listLocalMessagesAddMessages(Account account, - String folder, List messages) + public void listLocalMessagesAddMessages(final Account account, + final String folderName, final List messages) { + // cache fields into local variables for faster access on JVM without JIT + final MessageHelper helper = mMessageHelper; + final List holders = mHolders; + + final Context context = getContext(); + for (final Message message : messages) { - holders.add(new MessageInfoHolder(getContext(), message)); + final MessageInfoHolder messageInfoHolder = new MessageInfoHolder(); + final Folder messageFolder = message.getFolder(); + final Account messageAccount = messageFolder.getAccount(); + + helper.populate(messageInfoHolder, message, new FolderInfoHolder(context, + messageFolder, messageAccount), messageAccount); + + holders.add(messageInfoHolder); } } @@ -256,7 +272,7 @@ public class MessageProvider extends ContentProvider { try { - queue.put(holders); + queue.put(mHolders); } catch (InterruptedException e) { @@ -293,9 +309,13 @@ public class MessageProvider extends ContentProvider */ private List mQueryHandlers = new ArrayList(); + private MessageHelper mMessageHelper; + @Override public boolean onCreate() { + mMessageHelper = MessageHelper.getInstance(getContext()); + registerQueryHandler(new AccountsQueryHandler()); registerQueryHandler(new MessagesQueryHandler()); registerQueryHandler(new UnreadQueryHandler());