Fix threading issues in LiveRecipient.
This commit is contained in:
parent
af2990fa08
commit
82b5d58d04
1 changed files with 40 additions and 29 deletions
|
@ -17,6 +17,7 @@ import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
|
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
|
||||||
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
@ -25,14 +26,17 @@ import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
public final class LiveRecipient {
|
public final class LiveRecipient {
|
||||||
|
|
||||||
|
private static final String TAG = Log.tag(LiveRecipient.class);
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final MutableLiveData<Recipient> liveData;
|
private final MutableLiveData<Recipient> liveData;
|
||||||
private final Set<RecipientForeverObserver> observers;
|
private final Set<RecipientForeverObserver> observers;
|
||||||
private final Observer<Recipient> foreverObserver;
|
private final Observer<Recipient> foreverObserver;
|
||||||
private final Recipient defaultRecipient;
|
private final AtomicReference<Recipient> recipient;
|
||||||
private final RecipientDatabase recipientDatabase;
|
private final RecipientDatabase recipientDatabase;
|
||||||
private final GroupDatabase groupDatabase;
|
private final GroupDatabase groupDatabase;
|
||||||
private final String unnamedGroupName;
|
private final String unnamedGroupName;
|
||||||
|
@ -40,7 +44,7 @@ public final class LiveRecipient {
|
||||||
LiveRecipient(@NonNull Context context, @NonNull MutableLiveData<Recipient> liveData, @NonNull Recipient defaultRecipient) {
|
LiveRecipient(@NonNull Context context, @NonNull MutableLiveData<Recipient> liveData, @NonNull Recipient defaultRecipient) {
|
||||||
this.context = context.getApplicationContext();
|
this.context = context.getApplicationContext();
|
||||||
this.liveData = liveData;
|
this.liveData = liveData;
|
||||||
this.defaultRecipient = defaultRecipient;
|
this.recipient = new AtomicReference<>(defaultRecipient);
|
||||||
this.recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
|
this.recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
|
||||||
this.groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
this.groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||||
this.unnamedGroupName = context.getString(R.string.RecipientProvider_unnamed_group);
|
this.unnamedGroupName = context.getString(R.string.RecipientProvider_unnamed_group);
|
||||||
|
@ -53,20 +57,14 @@ public final class LiveRecipient {
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull RecipientId getId() {
|
public @NonNull RecipientId getId() {
|
||||||
return defaultRecipient.getId();
|
return recipient.get().getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return A recipient that may or may not be fully-resolved.
|
* @return A recipient that may or may not be fully-resolved.
|
||||||
*/
|
*/
|
||||||
public @NonNull Recipient get() {
|
public @NonNull Recipient get() {
|
||||||
Recipient live = liveData.getValue();
|
return recipient.get();
|
||||||
|
|
||||||
if (live == null) {
|
|
||||||
return defaultRecipient;
|
|
||||||
} else {
|
|
||||||
return live;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -118,27 +116,31 @@ public final class LiveRecipient {
|
||||||
* @return A fully-resolved version of the recipient. May require reading from disk.
|
* @return A fully-resolved version of the recipient. May require reading from disk.
|
||||||
*/
|
*/
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public @NonNull Recipient resolve() {
|
public synchronized @NonNull Recipient resolve() {
|
||||||
Recipient current = get();
|
Recipient current = recipient.get();
|
||||||
|
|
||||||
if (!current.isResolving()) {
|
if (!current.isResolving()) {
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
Recipient updated = fetchRecipientFromDisk(defaultRecipient.getId());
|
if (Util.isMainThread()) {
|
||||||
|
Log.w(TAG, "[Resolve][MAIN] " + getId(), new Throwable());
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "[Resolve][" + Thread.currentThread().getName() + "] " + getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
Recipient updated = fetchRecipientFromDisk(getId());
|
||||||
List<Recipient> participants = Stream.of(updated.getParticipants())
|
List<Recipient> participants = Stream.of(updated.getParticipants())
|
||||||
.filter(Recipient::isResolving)
|
.filter(Recipient::isResolving)
|
||||||
.map(Recipient::getId)
|
.map(Recipient::getId)
|
||||||
.map(this::fetchRecipientFromDisk)
|
.map(this::fetchRecipientFromDisk)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
Util.runOnMainSync(() -> {
|
for (Recipient participant : participants) {
|
||||||
for (Recipient participant : participants) {
|
participant.live().set(participant);
|
||||||
participant.live().liveData.setValue(participant);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
liveData.setValue(updated);
|
set(updated);
|
||||||
});
|
|
||||||
|
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
@ -148,19 +150,23 @@ public final class LiveRecipient {
|
||||||
*/
|
*/
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public void refresh() {
|
public void refresh() {
|
||||||
Recipient recipient = fetchRecipientFromDisk(defaultRecipient.getId());
|
if (Util.isMainThread()) {
|
||||||
|
Log.w(TAG, "[Refresh][MAIN] " + getId(), new Throwable());
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "[Refresh][" + Thread.currentThread().getName() + "] " + getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
Recipient recipient = fetchRecipientFromDisk(getId());
|
||||||
List<Recipient> participants = Stream.of(recipient.getParticipants())
|
List<Recipient> participants = Stream.of(recipient.getParticipants())
|
||||||
.map(Recipient::getId)
|
.map(Recipient::getId)
|
||||||
.map(this::fetchRecipientFromDisk)
|
.map(this::fetchRecipientFromDisk)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
Util.runOnMainSync(() -> {
|
for (Recipient participant : participants) {
|
||||||
for (Recipient participant : participants) {
|
participant.live().set(participant);
|
||||||
participant.live().liveData.setValue(participant);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
liveData.setValue(recipient);
|
set(recipient);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull Recipient fetchRecipientFromDisk(RecipientId id) {
|
private @NonNull Recipient fetchRecipientFromDisk(RecipientId id) {
|
||||||
|
@ -183,7 +189,7 @@ public final class LiveRecipient {
|
||||||
|
|
||||||
if (groupRecord.isPresent()) {
|
if (groupRecord.isPresent()) {
|
||||||
String title = groupRecord.get().getTitle();
|
String title = groupRecord.get().getTitle();
|
||||||
List<Recipient> members = Stream.of(groupRecord.get().getMembers()).map(Recipient::resolved).toList();
|
List<Recipient> members = Stream.of(groupRecord.get().getMembers()).map(this::fetchRecipientFromDisk).toList();
|
||||||
Optional<Long> avatarId = Optional.absent();
|
Optional<Long> avatarId = Optional.absent();
|
||||||
|
|
||||||
if (!settings.getAddress().isMmsGroup() && title == null) {
|
if (!settings.getAddress().isMmsGroup() && title == null) {
|
||||||
|
@ -200,16 +206,21 @@ public final class LiveRecipient {
|
||||||
return new RecipientDetails(context, unnamedGroupName, Optional.absent(), false, false, settings, null);
|
return new RecipientDetails(context, unnamedGroupName, Optional.absent(), false, false, settings, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private synchronized void set(@NonNull Recipient recipient) {
|
||||||
|
this.recipient.set(recipient);
|
||||||
|
this.liveData.postValue(recipient);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
LiveRecipient that = (LiveRecipient) o;
|
LiveRecipient that = (LiveRecipient) o;
|
||||||
return defaultRecipient.equals(that.defaultRecipient);
|
return recipient.equals(that.recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(defaultRecipient);
|
return Objects.hash(recipient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue