From 465172f1c7289f809a3e6091e08508e3478a4dd4 Mon Sep 17 00:00:00 2001 From: Daniel Applebaum Date: Fri, 6 Feb 2009 04:28:29 +0000 Subject: [PATCH] Fix threading in Accounts main screen. Move all UI updates to UI thread. Push unread message counting into the background. Should increase startup performance and reduce black-screens-of-death that some Market "commentators" report. Also, updates the per-account unread message count when email account is finished synchronizing. --- .../android/email/MessagingController.java | 23 ++++ src/com/android/email/MessagingListener.java | 4 + src/com/android/email/activity/Accounts.java | 107 +++++++++++++++--- 3 files changed, 120 insertions(+), 14 deletions(-) diff --git a/src/com/android/email/MessagingController.java b/src/com/android/email/MessagingController.java index d2822b7fb..b55ed78b8 100644 --- a/src/com/android/email/MessagingController.java +++ b/src/com/android/email/MessagingController.java @@ -1533,6 +1533,7 @@ s * critical data as fast as possible, and then we'll fill in the de queuePendingCommand(account, command); processPendingCommands(account); } + @@ -1985,6 +1986,28 @@ s * critical data as fast as possible, and then we'll fill in the de } } + public void getAccountUnreadCount(final Context context, final Account account, + final MessagingListener l) + { + Runnable unreadRunnable = new Runnable() { + public void run() { + + int unreadMessageCount = 0; + try { + unreadMessageCount = account.getUnreadMessageCount(context, mApplication); + } + catch (MessagingException me) { + Log.e(Email.LOG_TAG, "Count not get unread count for account " + account.getDescription(), + me); + } + l.accountStatusChanged(account, unreadMessageCount); + } + }; + + + putBackground("getAccountUnread:" + account.getDescription(), l, unreadRunnable); + } + public void deleteMessage(final Account account, final String folder, final Message message, final MessagingListener listener) { suppressMessage(account, folder, message); diff --git a/src/com/android/email/MessagingListener.java b/src/com/android/email/MessagingListener.java index 73f86c5b2..3f561568a 100644 --- a/src/com/android/email/MessagingListener.java +++ b/src/com/android/email/MessagingListener.java @@ -15,6 +15,10 @@ import com.android.email.mail.Part; * changes in this class. */ public class MessagingListener { + + public void accountStatusChanged(Account account, int unreadMessageCount) { + } + public void listFoldersStarted(Account account) { } diff --git a/src/com/android/email/activity/Accounts.java b/src/com/android/email/activity/Accounts.java index 9d2e5ff58..1e87285f9 100644 --- a/src/com/android/email/activity/Accounts.java +++ b/src/com/android/email/activity/Accounts.java @@ -1,6 +1,8 @@ package com.android.email.activity; +import java.util.concurrent.ConcurrentHashMap; + import android.app.AlertDialog; import android.app.Dialog; import android.app.ListActivity; @@ -11,6 +13,7 @@ import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Bundle; +import android.os.Handler; import android.view.ContextMenu; import android.view.KeyEvent; import android.view.Menu; @@ -32,6 +35,7 @@ import android.widget.AdapterView.OnItemClickListener; import com.android.email.Account; import com.android.email.Email; import com.android.email.MessagingController; +import com.android.email.MessagingListener; import com.android.email.Preferences; import com.android.email.R; import com.android.email.activity.setup.AccountSettings; @@ -45,6 +49,7 @@ import com.android.email.mail.store.LocalStore.LocalFolder; public class Accounts extends ListActivity implements OnItemClickListener, OnClickListener { private static final int DIALOG_REMOVE_ACCOUNT = 1; + private ConcurrentHashMap unreadMessageCounts = new ConcurrentHashMap(); /** * Key codes used to open a debug settings screen. */ @@ -55,7 +60,56 @@ public class Accounts extends ListActivity implements OnItemClickListener, OnCli private int mSecretKeyCodeIndex = 0; private Account mSelectedContextAccount; + + private AccountsHandler mHandler = new AccountsHandler(); + private AccountsAdapter mAdapter; + + class AccountsHandler extends Handler + { + private static final int DATA_CHANGED = 1; + public void handleMessage(android.os.Message msg) + { + switch (msg.what) + { + case DATA_CHANGED: + if (mAdapter != null) + { + mAdapter.notifyDataSetChanged(); + } + break; + default: + super.handleMessage(msg); + } + } + + public void dataChanged() + { + sendEmptyMessage(DATA_CHANGED); + } + + } + + MessagingListener mListener = new MessagingListener() { + @Override + public void accountStatusChanged(Account account, int unreadMessageCount) + { + unreadMessageCounts.put(account.getUuid(), unreadMessageCount); + mHandler.dataChanged(); + } + + @Override + public void synchronizeMailboxFinished( + Account account, + String folder, + int totalMessagesInMailbox, + int numNewMessages) { + MessagingController.getInstance(getApplication()).getAccountUnreadCount(Accounts.this, account, mListener); + } + }; + + private static String UNREAD_MESSAGE_COUNTS = "unreadMessageCounts"; + private static String SELECTED_CONTEXT_ACCOUNT = "selectedContextAccount"; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); @@ -67,17 +121,26 @@ public class Accounts extends ListActivity implements OnItemClickListener, OnCli findViewById(R.id.add_new_account).setOnClickListener(this); registerForContextMenu(listView); - if (icicle != null && icicle.containsKey("selectedContextAccount")) { + if (icicle != null && icicle.containsKey(SELECTED_CONTEXT_ACCOUNT)) { mSelectedContextAccount = (Account) icicle.getSerializable("selectedContextAccount"); } + if (icicle != null) + { + ConcurrentHashMap oldUnreadMessageCounts = + (ConcurrentHashMap)icicle.get(UNREAD_MESSAGE_COUNTS); + if (oldUnreadMessageCounts != null) { + unreadMessageCounts.putAll(oldUnreadMessageCounts); + } + } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); if (mSelectedContextAccount != null) { - outState.putSerializable("selectedContextAccount", mSelectedContextAccount); + outState.putSerializable(SELECTED_CONTEXT_ACCOUNT, mSelectedContextAccount); } + outState.putSerializable(UNREAD_MESSAGE_COUNTS, unreadMessageCounts); } @Override @@ -85,11 +148,26 @@ public class Accounts extends ListActivity implements OnItemClickListener, OnCli super.onResume(); refresh(); + MessagingController.getInstance(getApplication()).addListener(mListener); + } + + @Override + public void onPause() + { + super.onPause(); + MessagingController.getInstance(getApplication()).removeListener(mListener); } private void refresh() { Account[] accounts = Preferences.getPreferences(this).getAccounts(); - getListView().setAdapter(new AccountsAdapter(accounts)); + mAdapter = new AccountsAdapter(accounts); + getListView().setAdapter(mAdapter); + + for (Account account : accounts) + { + MessagingController.getInstance(getApplication()).getAccountUnreadCount(Accounts.this, account, mListener); + } + } private void onAddNewAccount() { @@ -305,7 +383,7 @@ getPackageManager().getPackageInfo(getPackageName(), 0); public AccountsAdapter(Account[] accounts) { super(Accounts.this, 0, accounts); } - + @Override public View getView(int position, View convertView, ViewGroup parent) { Account account = getItem(position); @@ -329,18 +407,19 @@ getPackageManager().getPackageInfo(getPackageName(), 0); if (account.getEmail().equals(account.getDescription())) { holder.email.setVisibility(View.GONE); } - int unreadMessageCount = 0; - try { - unreadMessageCount = account.getUnreadMessageCount(Accounts.this, getApplication()); + + Integer unreadMessageCount = unreadMessageCounts.get(account.getUuid()); + if (unreadMessageCount != null) + { + holder.newMessageCount.setText(Integer.toString(unreadMessageCount)); + holder.newMessageCount.setVisibility(unreadMessageCount > 0 ? View.VISIBLE : View.GONE); } - catch (MessagingException me) { - /* - * This is not expected to fail under normal circumstances. - */ - throw new RuntimeException("Unable to get unread count from local store.", me); + else + { + //holder.newMessageCount.setText("-"); + holder.newMessageCount.setVisibility(View.GONE); } - holder.newMessageCount.setText(Integer.toString(unreadMessageCount)); - holder.newMessageCount.setVisibility(unreadMessageCount > 0 ? View.VISIBLE : View.GONE); + return view; }