mirror of
https://github.com/moparisthebest/k-9
synced 2024-12-25 00:58:50 -05:00
Clone Message object to avoid ConcurrentModificationExceptions
Fixes issue 3953
This commit is contained in:
parent
4b5189973b
commit
71174417ce
@ -1123,12 +1123,28 @@ public class MessageView extends K9Activity implements OnClickListener {
|
||||
return;
|
||||
}
|
||||
MessageView.this.mMessage = message;
|
||||
|
||||
/*
|
||||
* Clone the message object because the original could be modified by
|
||||
* MessagingController later. This could lead to a ConcurrentModificationException
|
||||
* when that same object is accessed by the UI thread (below).
|
||||
*
|
||||
* See issue 3953
|
||||
*
|
||||
* This is just an ugly hack to get rid of the most pressing problem. A proper way to
|
||||
* fix this is to make Message thread-safe. Or, even better, rewriting the UI code to
|
||||
* access messages via a ContentProvider.
|
||||
*
|
||||
*/
|
||||
final Message clonedMessage = message.clone();
|
||||
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if (!message.isSet(Flag.X_DOWNLOADED_FULL) && !message.isSet(Flag.X_DOWNLOADED_PARTIAL)) {
|
||||
if (!clonedMessage.isSet(Flag.X_DOWNLOADED_FULL) &&
|
||||
!clonedMessage.isSet(Flag.X_DOWNLOADED_PARTIAL)) {
|
||||
mMessageView.loadBodyFromUrl("file:///android_asset/downloading.html");
|
||||
}
|
||||
mMessageView.setHeaders(message, account);
|
||||
mMessageView.setHeaders(clonedMessage, account);
|
||||
mMessageView.setOnFlagListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -224,4 +224,32 @@ public abstract class Message implements Part, Body {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the contents of this object into another {@code Message} object.
|
||||
*
|
||||
* @param destination
|
||||
* The {@code Message} object to receive the contents of this instance.
|
||||
*/
|
||||
protected void copy(Message destination) {
|
||||
destination.mUid = mUid;
|
||||
destination.mInternalDate = mInternalDate;
|
||||
destination.mFolder = mFolder;
|
||||
destination.mReference = mReference;
|
||||
|
||||
// mFlags contents can change during the object lifetime, so copy the Set
|
||||
destination.mFlags = new HashSet<Flag>(mFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code Message} object with the same content as this object.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Note:</strong>
|
||||
* This method was introduced as a hack to prevent {@code ConcurrentModificationException}s. It
|
||||
* shouldn't be used unless absolutely necessary. See the comment in
|
||||
* {@link com.fsck.k9.activity.MessageView.Listener#loadMessageForViewHeadersAvailable(com.fsck.k9.Account, String, String, Message)}
|
||||
* for more information.
|
||||
* </p>
|
||||
*/
|
||||
public abstract Message clone();
|
||||
}
|
||||
|
@ -133,9 +133,9 @@ public class MimeHeader {
|
||||
}
|
||||
|
||||
static class Field {
|
||||
String name;
|
||||
final String name;
|
||||
|
||||
String value;
|
||||
final String value;
|
||||
|
||||
public Field(String name, String value) {
|
||||
this.name = name;
|
||||
@ -153,4 +153,13 @@ public class MimeHeader {
|
||||
public void setCharset(String charset) {
|
||||
mCharset = charset;
|
||||
}
|
||||
|
||||
public MimeHeader clone() {
|
||||
MimeHeader header = new MimeHeader();
|
||||
header.mCharset = mCharset;
|
||||
|
||||
header.mFields = new ArrayList<Field>(mFields);
|
||||
|
||||
return header;
|
||||
}
|
||||
}
|
||||
|
@ -553,4 +553,38 @@ public class MimeMessage extends Message {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the contents of this object into another {@code MimeMessage} object.
|
||||
*
|
||||
* @param message
|
||||
* The {@code MimeMessage} object to receive the contents of this instance.
|
||||
*/
|
||||
protected void copy(MimeMessage message) {
|
||||
super.copy(message);
|
||||
|
||||
message.mHeader = mHeader.clone();
|
||||
|
||||
message.mBody = mBody;
|
||||
message.mMessageId = mMessageId;
|
||||
message.mSentDate = mSentDate;
|
||||
message.mDateFormat = mDateFormat;
|
||||
message.mSize = mSize;
|
||||
|
||||
// These arrays are not supposed to be modified, so it's okay to reuse the references
|
||||
message.mFrom = mFrom;
|
||||
message.mTo = mTo;
|
||||
message.mCc = mCc;
|
||||
message.mBcc = mBcc;
|
||||
message.mReplyTo = mReplyTo;
|
||||
message.mReferences = mReferences;
|
||||
message.mInReplyTo = mInReplyTo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MimeMessage clone() {
|
||||
MimeMessage message = new MimeMessage();
|
||||
copy(message);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
@ -3310,6 +3310,25 @@ public class LocalStore extends Store implements Serializable {
|
||||
loadHeaders();
|
||||
return super.getHeaderNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalMessage clone() {
|
||||
LocalMessage message = new LocalMessage();
|
||||
super.copy(message);
|
||||
|
||||
message.mId = mId;
|
||||
message.mAttachmentCount = mAttachmentCount;
|
||||
message.mSubject = mSubject;
|
||||
message.mPreview = mPreview;
|
||||
message.mToMeCalculated = mToMeCalculated;
|
||||
message.mCcMeCalculated = mCcMeCalculated;
|
||||
message.mToMe = mToMe;
|
||||
message.mCcMe = mCcMe;
|
||||
message.mHeadersLoaded = mHeadersLoaded;
|
||||
message.mMessageDirty = mMessageDirty;
|
||||
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
public static class LocalAttachmentBodyPart extends MimeBodyPart {
|
||||
|
Loading…
Reference in New Issue
Block a user