Fix bug 4982804 / nested fragment transaction
Post MessageOrderManager callbacks instead of calling them directly to break the loop. Change-Id: I033121f7bdbadf6edd7a0fab87b960b737da820e
This commit is contained in:
parent
8067daaa0f
commit
2ac164f609
@ -19,8 +19,10 @@ package com.android.email.activity;
|
|||||||
import com.android.emailcommon.provider.EmailContent;
|
import com.android.emailcommon.provider.EmailContent;
|
||||||
import com.android.emailcommon.provider.EmailContent.Message;
|
import com.android.emailcommon.provider.EmailContent.Message;
|
||||||
import com.android.emailcommon.provider.Mailbox;
|
import com.android.emailcommon.provider.Mailbox;
|
||||||
|
import com.android.emailcommon.utility.DelayedOperations;
|
||||||
import com.android.emailcommon.utility.EmailAsyncTask;
|
import com.android.emailcommon.utility.EmailAsyncTask;
|
||||||
import com.android.emailcommon.utility.Utility;
|
import com.android.emailcommon.utility.Utility;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
@ -56,6 +58,7 @@ public class MessageOrderManager {
|
|||||||
private final long mMailboxId;
|
private final long mMailboxId;
|
||||||
private final ContentObserver mObserver;
|
private final ContentObserver mObserver;
|
||||||
private final Callback mCallback;
|
private final Callback mCallback;
|
||||||
|
private final DelayedOperations mDelayedOperations;
|
||||||
|
|
||||||
private LoadMessageListTask mLoadMessageListTask;
|
private LoadMessageListTask mLoadMessageListTask;
|
||||||
private Cursor mCursor;
|
private Cursor mCursor;
|
||||||
@ -81,12 +84,56 @@ public class MessageOrderManager {
|
|||||||
public void onMessageNotFound();
|
public void onMessageNotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for {@link Callback}, which uses {@link DelayedOperations#post(Runnable)} to
|
||||||
|
* kick callbacks rather than calling them directly. This is used to avoid the "nested fragment
|
||||||
|
* transaction" exception. e.g. {@link #moveTo} is often called during a fragment transaction,
|
||||||
|
* and if the message no longer exists we call {@link #onMessageNotFound}, which most probably
|
||||||
|
* triggers another fragment transaction.
|
||||||
|
*/
|
||||||
|
private class PostingCallback implements Callback {
|
||||||
|
private final Callback mOriginal;
|
||||||
|
|
||||||
|
private PostingCallback(Callback original) {
|
||||||
|
mOriginal = original;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Runnable mOnMessagesChangedRunnable = new Runnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
mOriginal.onMessagesChanged();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessagesChanged() {
|
||||||
|
mDelayedOperations.post(mOnMessagesChangedRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Runnable mOnMessageNotFoundRunnable = new Runnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
mOriginal.onMessageNotFound();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessageNotFound() {
|
||||||
|
mDelayedOperations.post(mOnMessageNotFoundRunnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public MessageOrderManager(Context context, long mailboxId, Callback callback) {
|
public MessageOrderManager(Context context, long mailboxId, Callback callback) {
|
||||||
|
this(context, mailboxId, callback, new DelayedOperations(Utility.getMainThreadHandler()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
MessageOrderManager(Context context, long mailboxId, Callback callback,
|
||||||
|
DelayedOperations delayedOperations) {
|
||||||
Preconditions.checkArgument(mailboxId != Mailbox.NO_MAILBOX);
|
Preconditions.checkArgument(mailboxId != Mailbox.NO_MAILBOX);
|
||||||
mContext = context.getApplicationContext();
|
mContext = context.getApplicationContext();
|
||||||
mContentResolver = mContext.getContentResolver();
|
mContentResolver = mContext.getContentResolver();
|
||||||
|
mDelayedOperations = delayedOperations;
|
||||||
mMailboxId = mailboxId;
|
mMailboxId = mailboxId;
|
||||||
mCallback = callback;
|
mCallback = new PostingCallback(callback);
|
||||||
mObserver = new ContentObserver(getHandlerForContentObserver()) {
|
mObserver = new ContentObserver(getHandlerForContentObserver()) {
|
||||||
@Override public void onChange(boolean selfChange) {
|
@Override public void onChange(boolean selfChange) {
|
||||||
if (mClosed) {
|
if (mClosed) {
|
||||||
@ -173,6 +220,7 @@ public class MessageOrderManager {
|
|||||||
*/
|
*/
|
||||||
public void close() {
|
public void close() {
|
||||||
mClosed = true;
|
mClosed = true;
|
||||||
|
mDelayedOperations.removeCallbacks();
|
||||||
cancelTask();
|
cancelTask();
|
||||||
closeCursor();
|
closeCursor();
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package com.android.email.activity;
|
|||||||
|
|
||||||
import com.android.email.provider.EmailProvider;
|
import com.android.email.provider.EmailProvider;
|
||||||
import com.android.emailcommon.provider.EmailContent;
|
import com.android.emailcommon.provider.EmailContent;
|
||||||
|
import com.android.emailcommon.utility.DelayedOperations;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.AbstractCursor;
|
import android.database.AbstractCursor;
|
||||||
@ -284,6 +285,20 @@ public class MessageOrderManagerTest extends ProviderTestCase2<EmailProvider> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Non" delayed operation -- runs the runnable immediately
|
||||||
|
*/
|
||||||
|
private static final class NonDelayedOperations extends DelayedOperations {
|
||||||
|
public NonDelayedOperations() {
|
||||||
|
super(new Handler());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void post(Runnable r) {
|
||||||
|
r.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MessageOrderManager for test. Overrides {@link #startQuery}
|
* MessageOrderManager for test. Overrides {@link #startQuery}
|
||||||
*/
|
*/
|
||||||
@ -292,7 +307,7 @@ public class MessageOrderManagerTest extends ProviderTestCase2<EmailProvider> {
|
|||||||
public boolean mStartQueryCalled;
|
public boolean mStartQueryCalled;
|
||||||
|
|
||||||
public MessageOrderManagerForTest(Context context, long mailboxId, Callback callback) {
|
public MessageOrderManagerForTest(Context context, long mailboxId, Callback callback) {
|
||||||
super(context, mailboxId, callback);
|
super(context, mailboxId, callback, new NonDelayedOperations());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override void startQuery() {
|
@Override void startQuery() {
|
||||||
|
Loading…
Reference in New Issue
Block a user