Clean up MailboxListFragment.

- Remove AsyncTasks, and use CursorLoader to load data.
- Get message counts for the drafts/trash mailboxes directly from
  the db column.
- Remove obsolete code from MailboxesAdapter.

Change-Id: I93c72977c19b60581e1169ba9bd429912ba3e68f
This commit is contained in:
Makoto Onuki 2010-08-02 16:05:07 -07:00
parent d0c2178063
commit 7ef278202e
3 changed files with 91 additions and 263 deletions

View File

@ -45,12 +45,6 @@
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary" />
<TextView
android:id="@+id/mailbox_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorTertiary" />
</LinearLayout>
<TextView
android:id="@+id/new_message_count"

View File

@ -17,23 +17,15 @@
package com.android.email.activity;
import com.android.email.Email;
import com.android.email.R;
import com.android.email.Utility;
import com.android.email.provider.EmailContent;
import com.android.email.provider.EmailContent.Mailbox;
import com.android.email.provider.EmailContent.MailboxColumns;
import com.android.email.provider.EmailContent.Message;
import com.android.email.provider.EmailContent.MessageColumns;
import android.app.Activity;
import android.app.ListFragment;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.Loader;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
@ -50,23 +42,14 @@ import java.security.InvalidParameterException;
* - pass-through implementations of onCreateContextMenu() and onContextItemSelected() (temporary)
*/
public class MailboxListFragment extends ListFragment implements OnItemClickListener {
private static final String MAILBOX_SELECTION = MailboxColumns.ACCOUNT_KEY + "=?" +
" AND " + MailboxColumns.TYPE + "<" + Mailbox.TYPE_NOT_EMAIL +
" AND " + MailboxColumns.FLAG_VISIBLE + "=1";
private static final String MESSAGE_MAILBOX_ID_SELECTION = MessageColumns.MAILBOX_KEY + "=?";
// Account & mailboxes access
private static final int LOADER_ID_MAILBOX_LIST = 1;
private long mAccountId = -1;
private LoadMailboxesTask mLoadMailboxesTask;
private MessageCountTask mMessageCountTask;
private long mDraftMailboxKey = -1;
private long mTrashMailboxKey = -1;
// UI Support
private Activity mActivity;
private MailboxesAdapter mListAdapter;
private Callback mCallback = EmptyCallback.INSTANCE;
private final MyLoaderCallbacks mMyLoaderCallbacks = new MyLoaderCallbacks();
private boolean mStarted;
@ -150,6 +133,7 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Email.LOG_TAG, "MailboxListFragment onStart");
}
getLoaderManager(); // TODO Work around internal bug 2887723.
super.onStart();
mStarted = true;
if (mAccountId != -1) {
@ -166,7 +150,6 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
Log.d(Email.LOG_TAG, "MailboxListFragment onResume");
}
super.onResume();
updateMessageCount();
}
@Override
@ -187,7 +170,6 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
}
mStarted = false;
super.onStop();
cancelAllTasks();
}
/**
@ -199,8 +181,6 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
Log.d(Email.LOG_TAG, "MailboxListFragment onDestroy");
}
super.onDestroy();
mListAdapter.changeCursor(null);
}
@Override
@ -211,166 +191,41 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
super.onSaveInstanceState(outState);
}
private void cancelAllTasks() {
Utility.cancelTaskInterrupt(mLoadMailboxesTask);
mLoadMailboxesTask = null;
Utility.cancelTaskInterrupt(mMessageCountTask);
mMessageCountTask = null;
}
private void startLoading() {
cancelAllTasks();
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Email.LOG_TAG, "MailboxListFragment startLoading");
}
// Clear the list. (ListFragment will show the "Loading" animation)
setListAdapter(null);
setListShown(false);
mLoadMailboxesTask = new LoadMailboxesTask(mAccountId);
mLoadMailboxesTask.execute();
getLoaderManager().restartLoader(LOADER_ID_MAILBOX_LIST, null, mMyLoaderCallbacks);
}
/**
* This is called via the activity
* TODO This will be removed when possible
*/
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo info) {
AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) info;
Cursor c = (Cursor) getListView().getItemAtPosition(menuInfo.position);
String folderName = Utility.FolderProperties.getInstance(mActivity)
.getDisplayName(Integer.valueOf(c.getString(mListAdapter.COLUMN_TYPE)));
if (folderName == null) {
folderName = c.getString(mListAdapter.COLUMN_DISPLAY_NAME);
private class MyLoaderCallbacks implements LoaderCallbacks<Cursor> {
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Email.LOG_TAG, "MailboxListFragment onCreateLoader");
}
return MailboxesAdapter.createLoader(getActivity(), mAccountId);
}
menu.setHeaderTitle(folderName);
mActivity.getMenuInflater().inflate(R.menu.mailbox_list_context, menu);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Email.LOG_TAG, "MailboxListFragment onLoadFinished");
}
/**
* This is called via the activity
* TODO This will be removed when possible
*/
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId()) {
case R.id.refresh:
mCallback.onRefresh(mAccountId, info.id);
return true;
case R.id.open:
mCallback.onMailboxSelected(mAccountId, info.id);
return true;
final ListView lv = getListView();
final Parcelable listState = lv.onSaveInstanceState();
mListAdapter.changeCursor(cursor);
setListAdapter(mListAdapter);
setListShown(true);
lv.onRestoreInstanceState(listState);
}
return false;
}
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mCallback.onMailboxSelected(mAccountId, id);
}
/**
* Async task for loading the mailboxes for a given account
*/
private class LoadMailboxesTask extends AsyncTask<Void, Void, Object[]> {
private long mAccountKey;
/**
* Special constructor to cache some local info
*/
public LoadMailboxesTask(long accountId) {
mAccountKey = accountId;
mDraftMailboxKey = -1;
mTrashMailboxKey = -1;
}
@Override
protected Object[] doInBackground(Void... params) {
long draftMailboxKey = -1;
long trashMailboxKey = -1;
Cursor c = mActivity.managedQuery(
EmailContent.Mailbox.CONTENT_URI,
mListAdapter.PROJECTION,
MAILBOX_SELECTION,
new String[] { String.valueOf(mAccountKey) },
MailboxColumns.TYPE + "," + MailboxColumns.DISPLAY_NAME);
c.moveToPosition(-1);
while (c.moveToNext()) {
long mailboxId = c.getInt(mListAdapter.COLUMN_ID);
switch (c.getInt(mListAdapter.COLUMN_TYPE)) {
case Mailbox.TYPE_DRAFTS:
draftMailboxKey = mailboxId;
break;
case Mailbox.TYPE_TRASH:
trashMailboxKey = mailboxId;
break;
}
}
Object[] result = new Object[3];
result[0] = c;
result[1] = draftMailboxKey;
result[2] = trashMailboxKey;
return result;
}
@Override
protected void onPostExecute(Object[] results) {
if (results == null || isCancelled()) return;
Cursor cursor = (Cursor) results[0];
mDraftMailboxKey = (Long) results[1];
mTrashMailboxKey = (Long) results[2];
if (cursor.isClosed()) return;
mListAdapter.changeCursor(cursor);
setListAdapter(mListAdapter);
updateMessageCount();
}
}
private class MessageCountTask extends AsyncTask<Void, Void, int[]> {
@Override
protected int[] doInBackground(Void... params) {
int[] counts = new int[2];
if (mDraftMailboxKey != -1) {
counts[0] = EmailContent.count(mActivity, Message.CONTENT_URI,
MESSAGE_MAILBOX_ID_SELECTION,
new String[] { String.valueOf(mDraftMailboxKey)});
} else {
counts[0] = 0;
}
if (mTrashMailboxKey != -1) {
counts[1] = EmailContent.count(mActivity, Message.CONTENT_URI,
MESSAGE_MAILBOX_ID_SELECTION,
new String[] { String.valueOf(mTrashMailboxKey)});
} else {
counts[1] = 0;
}
return counts;
}
@Override
protected void onPostExecute(int[] counts) {
if (counts == null || isCancelled()) {
return;
}
int countDraft = counts[0];
int countTrash = counts[1];
mListAdapter.setMessageCounts(countDraft, countTrash);
}
}
private void updateMessageCount() {
if (mAccountId == -1 || mListAdapter.getCursor() == null) {
return;
}
if (mMessageCountTask != null
&& mMessageCountTask.getStatus() != MessageCountTask.Status.FINISHED) {
mMessageCountTask.cancel(true);
}
mMessageCountTask = (MessageCountTask) new MessageCountTask().execute();
}
}

View File

@ -16,13 +16,15 @@
package com.android.email.activity;
import com.android.email.Email;
import com.android.email.R;
import com.android.email.Utility;
import com.android.email.provider.EmailContent;
import com.android.email.provider.EmailContent.Mailbox;
import com.android.email.provider.EmailContent.MailboxColumns;
import android.content.Context;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.graphics.Typeface;
import android.view.LayoutInflater;
@ -34,115 +36,80 @@ import android.widget.TextView;
/**
* The adapter for displaying mailboxes.
*
* TODO Add "combined inbox/star/etc.".
* TODO Throttle auto-requery.
* TODO Unit test, when UI is settled.
*/
/* package */ class MailboxesAdapter extends CursorAdapter {
private static final String[] PROJECTION = new String[] { MailboxColumns.ID,
MailboxColumns.DISPLAY_NAME, MailboxColumns.UNREAD_COUNT, MailboxColumns.TYPE,
MailboxColumns.MESSAGE_COUNT};
private static final int COLUMN_ID = 0;
private static final int COLUMN_DISPLAY_NAME = 1;
private static final int COLUMN_UNREAD_COUNT = 2;
private static final int COLUMN_TYPE = 3;
private static final int COLUMN_MESSAGE_COUNT = 4;
public final String[] PROJECTION = new String[] { MailboxColumns.ID,
MailboxColumns.DISPLAY_NAME, MailboxColumns.UNREAD_COUNT, MailboxColumns.TYPE };
public final int COLUMN_ID = 0;
public final int COLUMN_DISPLAY_NAME = 1;
public final int COLUMN_UNREAD_COUNT = 2;
public final int COLUMN_TYPE = 3;
private static final String MAILBOX_SELECTION = MailboxColumns.ACCOUNT_KEY + "=?" +
" AND " + MailboxColumns.TYPE + "<" + Mailbox.TYPE_NOT_EMAIL +
" AND " + MailboxColumns.FLAG_VISIBLE + "=1";
private final LayoutInflater mInflater;
private long mAccountId;
private int mUnreadCountDraft;
private int mUnreadCountTrash;
public MailboxesAdapter(Context context) {
super(context, null);
super(context, null, 0 /* no auto-requery */);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
/**
* Set account Id (which may become available after creation)
* TODO simplify the caller to just provide this at constructor time
*/
public void setAccountId(long accountId) {
mAccountId = accountId;
}
/**
* Set special read/unread counts (not taken from the row).
*/
public void setMessageCounts(int numDrafts, int numTrash) {
boolean countChanged = (mUnreadCountDraft != numDrafts) || (mUnreadCountTrash != numTrash);
if (countChanged) {
mUnreadCountDraft = numDrafts;
mUnreadCountTrash = numTrash;
notifyDataSetChanged();
}
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
int type = cursor.getInt(COLUMN_TYPE);
String text = Utility.FolderProperties.getInstance(context)
final int type = cursor.getInt(COLUMN_TYPE);
// Set mailbox name
final TextView nameView = (TextView) view.findViewById(R.id.mailbox_name);
String mailboxName = Utility.FolderProperties.getInstance(context)
.getDisplayName(type);
if (text == null) {
text = cursor.getString(COLUMN_DISPLAY_NAME);
if (mailboxName == null) {
mailboxName = cursor.getString(COLUMN_DISPLAY_NAME);
}
TextView nameView = (TextView) view.findViewById(R.id.mailbox_name);
if (text != null) {
nameView.setText(text);
if (mailboxName != null) {
nameView.setText(mailboxName);
}
// TODO get/track live folder status
text = null;
TextView statusView = (TextView) view.findViewById(R.id.mailbox_status);
if (text != null) {
statusView.setText(text);
statusView.setVisibility(View.VISIBLE);
} else {
statusView.setVisibility(View.GONE);
}
View chipView = view.findViewById(R.id.chip);
chipView.setBackgroundResource(Email.getAccountColorResourceId(mAccountId));
int count = -1;
switch (type) {
case Mailbox.TYPE_DRAFTS:
count = mUnreadCountDraft;
text = String.valueOf(count);
break;
case Mailbox.TYPE_TRASH:
count = mUnreadCountTrash;
text = String.valueOf(count);
break;
default:
text = cursor.getString(COLUMN_UNREAD_COUNT);
if (text != null) {
count = Integer.valueOf(text);
}
break;
}
TextView unreadCountView = (TextView) view.findViewById(R.id.new_message_count);
TextView allCountView = (TextView) view.findViewById(R.id.all_message_count);
// Set count
final int count = cursor.getInt((type == Mailbox.TYPE_DRAFTS || type == Mailbox.TYPE_TRASH)
? COLUMN_MESSAGE_COUNT : COLUMN_UNREAD_COUNT);
final TextView unreadCountView = (TextView) view.findViewById(R.id.new_message_count);
final TextView allCountView = (TextView) view.findViewById(R.id.all_message_count);
// If the unread count is zero, not to show countView.
if (count > 0) {
nameView.setTypeface(Typeface.DEFAULT_BOLD);
switch (type) {
case Mailbox.TYPE_DRAFTS:
case Mailbox.TYPE_OUTBOX:
case Mailbox.TYPE_SENT:
case Mailbox.TYPE_TRASH:
unreadCountView.setVisibility(View.GONE);
allCountView.setVisibility(View.VISIBLE);
allCountView.setText(text);
break;
default:
allCountView.setVisibility(View.GONE);
unreadCountView.setVisibility(View.VISIBLE);
unreadCountView.setText(text);
break;
}
case Mailbox.TYPE_DRAFTS:
case Mailbox.TYPE_OUTBOX:
case Mailbox.TYPE_SENT:
case Mailbox.TYPE_TRASH:
unreadCountView.setVisibility(View.GONE);
allCountView.setVisibility(View.VISIBLE);
allCountView.setText(Integer.toString(count));
break;
default:
allCountView.setVisibility(View.GONE);
unreadCountView.setVisibility(View.VISIBLE);
unreadCountView.setText(Integer.toString(count));
break;
}
} else {
nameView.setTypeface(Typeface.DEFAULT);
allCountView.setVisibility(View.GONE);
unreadCountView.setVisibility(View.GONE);
}
ImageView folderIcon = (ImageView) view.findViewById(R.id.folder_icon);
folderIcon.setImageDrawable(Utility.FolderProperties.getInstance(context)
// Set folder icon
((ImageView) view.findViewById(R.id.folder_icon))
.setImageDrawable(Utility.FolderProperties.getInstance(context)
.getIconIds(type));
}
@ -150,4 +117,16 @@ import android.widget.TextView;
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return mInflater.inflate(R.layout.mailbox_list_item, parent, false);
}
/**
* @return mailboxes Loader for an account.
*/
public static Loader<Cursor> createLoader(Context context, long accountId) {
return new CursorLoader(context,
EmailContent.Mailbox.CONTENT_URI,
MailboxesAdapter.PROJECTION,
MAILBOX_SELECTION,
new String[] { String.valueOf(accountId) },
MailboxColumns.TYPE + "," + MailboxColumns.DISPLAY_NAME);
}
}