[android] address thread-safety issues of attachment creation

This commit is contained in:
Torsten Grote
2019-06-17 13:22:38 -03:00
parent 1f91842c52
commit ad2d3e70d6
2 changed files with 16 additions and 11 deletions

View File

@@ -103,7 +103,7 @@ public class AttachmentCreator {
AttachmentItemResult itemResult = AttachmentItemResult itemResult =
new AttachmentItemResult(uri, item); new AttachmentItemResult(uri, item);
itemResults.add(itemResult); itemResults.add(itemResult);
result.postValue(new AttachmentResult(itemResults, false)); result.postValue(getResult(false));
} catch (IOException | DbException e) { } catch (IOException | DbException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
onAttachmentError(uri, e); onAttachmentError(uri, e);
@@ -127,15 +127,13 @@ public class AttachmentCreator {
AttachmentItemResult itemResult = AttachmentItemResult itemResult =
new AttachmentItemResult(uri, errorMsg); new AttachmentItemResult(uri, errorMsg);
itemResults.add(itemResult); itemResults.add(itemResult);
result.postValue(new AttachmentResult(itemResults, false)); result.postValue(getResult(false));
// expect to receive a cancel from the UI // expect to receive a cancel from the UI
} }
@IoExecutor @IoExecutor
void onAttachmentCreationFinished() { void onAttachmentCreationFinished() {
if (uris.size() != itemResults.size()) result.postValue(getResult(true));
throw new IllegalStateException();
result.postValue(new AttachmentResult(itemResults, true));
} }
@UiThread @UiThread
@@ -205,4 +203,16 @@ public class AttachmentCreator {
}); });
} }
private AttachmentResult getResult(boolean finished) {
// Make a copy of the list,
// because our copy will continue to change in the background.
// (As it's a CopyOnWriteArrayList,
// the code that receives the result can safely do simple things
// like iterating over the list,
// but anything that involves calling more than one list method
// is still unsafe.)
Collection<AttachmentItemResult> items = new ArrayList<>(itemResults);
return new AttachmentResult(items, finished);
}
} }

View File

@@ -6,7 +6,6 @@ import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData; import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.Transformations; import android.arch.lifecycle.Transformations;
import android.net.Uri; import android.net.Uri;
import android.os.Handler;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.annotation.UiThread; import android.support.annotation.UiThread;
@@ -47,7 +46,6 @@ import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import static android.os.Looper.getMainLooper;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
@@ -294,6 +292,7 @@ public class ConversationViewModel extends AndroidViewModel
private void storeMessage(PrivateMessage m, @Nullable String text, private void storeMessage(PrivateMessage m, @Nullable String text,
List<AttachmentHeader> attachments) { List<AttachmentHeader> attachments) {
attachmentCreator.onAttachmentsSent(m.getMessage().getId());
dbExecutor.execute(() -> { dbExecutor.execute(() -> {
try { try {
long start = now(); long start = now();
@@ -304,10 +303,6 @@ public class ConversationViewModel extends AndroidViewModel
message.getId(), message.getGroupId(), message.getId(), message.getGroupId(),
message.getTimestamp(), true, true, false, false, message.getTimestamp(), true, true, false, false,
text != null, attachments); text != null, attachments);
MessageId id = m.getMessage().getId();
// use the UiThread to call onAttachmentsSent
new Handler(getMainLooper()).post(() ->
attachmentCreator.onAttachmentsSent(id));
// TODO add text to cache when available here // TODO add text to cache when available here
addedHeader.postEvent(h); addedHeader.postEvent(h);
} catch (DbException e) { } catch (DbException e) {