Remove ListenableFutureTask and replace it with LiveData

This commit is contained in:
Torsten Grote
2018-09-07 13:17:56 -03:00
parent 183fe08565
commit b78dfea95f
3 changed files with 55 additions and 193 deletions

View File

@@ -1,8 +1,11 @@
package org.briarproject.briar.android.contact; package org.briarproject.briar.android.contact;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.Observer;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread; import android.support.annotation.UiThread;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
@@ -72,8 +75,6 @@ import org.briarproject.briar.api.messaging.PrivateRequest;
import org.briarproject.briar.api.messaging.PrivateResponse; import org.briarproject.briar.api.messaging.PrivateResponse;
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent; import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
import org.thoughtcrime.securesms.components.util.FutureTaskListener;
import org.thoughtcrime.securesms.components.util.ListenableFutureTask;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@@ -81,13 +82,10 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import de.hdodenhof.circleimageview.CircleImageView; import de.hdodenhof.circleimageview.CircleImageView;
@@ -141,18 +139,6 @@ public class ConversationActivity extends BriarActivity
private BriarRecyclerView list; private BriarRecyclerView list;
private TextInputView textInputView; private TextInputView textInputView;
private final ListenableFutureTask<String> contactNameTask =
new ListenableFutureTask<>(new Callable<String>() {
@Override
public String call() throws Exception {
Contact c = contactManager.getContact(contactId);
contactName = c.getAuthor().getName();
return c.getAuthor().getName();
}
});
private final AtomicBoolean contactNameTaskStarted =
new AtomicBoolean(false);
// Fields that are accessed from background threads must be volatile // Fields that are accessed from background threads must be volatile
@Inject @Inject
volatile ContactManager contactManager; volatile ContactManager contactManager;
@@ -177,11 +163,10 @@ public class ConversationActivity extends BriarActivity
private volatile ContactId contactId; private volatile ContactId contactId;
@Nullable @Nullable
private volatile String contactName;
@Nullable
private volatile AuthorId contactAuthorId; private volatile AuthorId contactAuthorId;
@Nullable @Nullable
private volatile GroupId messagingGroupId; private volatile GroupId messagingGroupId;
private MutableLiveData<String> contactName = new MutableLiveData<>();
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
@Override @Override
@@ -292,7 +277,7 @@ public class ConversationActivity extends BriarActivity
long start = now(); long start = now();
if (contactName == null || contactAuthorId == null) { if (contactName == null || contactAuthorId == null) {
Contact contact = contactManager.getContact(contactId); Contact contact = contactManager.getContact(contactId);
contactName = contact.getAuthor().getName(); contactName.postValue(contact.getAuthor().getName());
contactAuthorId = contact.getAuthor().getId(); contactAuthorId = contact.getAuthor().getId();
} }
logDuration(LOG, "Loading contact", start); logDuration(LOG, "Loading contact", start);
@@ -306,12 +291,13 @@ public class ConversationActivity extends BriarActivity
}); });
} }
// contactAuthorId and contactName are expected to be set
private void displayContactDetails() { private void displayContactDetails() {
runOnUiThreadUnlessDestroyed(() -> { runOnUiThreadUnlessDestroyed(() -> {
//noinspection ConstantConditions //noinspection ConstantConditions
toolbarAvatar.setImageDrawable( toolbarAvatar.setImageDrawable(
new IdenticonDrawable(contactAuthorId.getBytes())); new IdenticonDrawable(contactAuthorId.getBytes()));
toolbarTitle.setText(contactName); toolbarTitle.setText(contactName.getValue());
}); });
} }
@@ -381,13 +367,13 @@ public class ConversationActivity extends BriarActivity
ConversationItem item; ConversationItem item;
if (h instanceof IntroductionResponse) { if (h instanceof IntroductionResponse) {
IntroductionResponse i = (IntroductionResponse) h; IntroductionResponse i = (IntroductionResponse) h;
item = ConversationItem.from(this, contactName, i); item = ConversationItem.from(this, contactName.getValue(), i);
} else if (h instanceof PrivateRequest) { } else if (h instanceof PrivateRequest) {
PrivateRequest r = (PrivateRequest) h; PrivateRequest r = (PrivateRequest) h;
item = ConversationItem.from(this, contactName, r); item = ConversationItem.from(this, contactName.getValue(), r);
} else if (h instanceof PrivateResponse) { } else if (h instanceof PrivateResponse) {
PrivateResponse r = (PrivateResponse) h; PrivateResponse r = (PrivateResponse) h;
item = ConversationItem.from(this, contactName, r); item = ConversationItem.from(this, contactName.getValue(), r);
} else { } else {
item = ConversationItem.from(h); item = ConversationItem.from(h);
String body = bodyCache.get(h.getId()); String body = bodyCache.get(h.getId());
@@ -480,43 +466,42 @@ public class ConversationActivity extends BriarActivity
} }
private void onNewPrivateMessage(PrivateMessageHeader h) { private void onNewPrivateMessage(PrivateMessageHeader h) {
if (h instanceof PrivateRequest || h instanceof PrivateResponse) { runOnUiThreadUnlessDestroyed(() -> {
getContactNameTask().addListener(new FutureTaskListener<String>() { if (h instanceof PrivateRequest) {
@Override contactName.observe(this, new Observer<String>() {
public void onSuccess(String contactName) { @Override
runOnUiThreadUnlessDestroyed( public void onChanged(@Nullable String name) {
() -> handlePrivateRequestAndResponse(h, if (name == null) loadContactName();
contactName)); else {
} PrivateRequest m = (PrivateRequest) h;
ConversationItem item = ConversationItem.from(
@Override ConversationActivity.this, name, m);
public void onFailure(Throwable exception) { addConversationItem(item);
runOnUiThreadUnlessDestroyed( contactName.removeObserver(this);
() -> handleDbException((DbException) exception)); }
} }
}); });
} else { if (contactName.getValue() == null) loadContactName();
addConversationItem(ConversationItem.from(h)); } else if (h instanceof PrivateResponse) {
loadMessageBody(h.getId()); contactName.observe(this, new Observer<String>() {
} @Override
} public void onChanged(@Nullable String name) {
if (name == null) loadContactName();
@UiThread else {
private void handlePrivateRequestAndResponse(PrivateMessageHeader h, PrivateResponse m = (PrivateResponse) h;
String contactName) { ConversationItem item = ConversationItem.from(
ConversationItem item; ConversationActivity.this, name, m);
if (h instanceof PrivateRequest) { addConversationItem(item);
PrivateRequest m = (PrivateRequest) h; contactName.removeObserver(this);
item = ConversationItem }
.from(ConversationActivity.this, contactName, m); }
} else if (h instanceof PrivateResponse) { });
PrivateResponse m = (PrivateResponse) h; if (contactName.getValue() == null) loadContactName();
item = ConversationItem } else {
.from(ConversationActivity.this, contactName, m); addConversationItem(ConversationItem.from(h));
} else { loadMessageBody(h.getId());
throw new AssertionError("Unknown PrivateMessageHeader"); }
} });
addConversationItem(item);
} }
private void markMessages(Collection<MessageId> messageIds, boolean sent, private void markMessages(Collection<MessageId> messageIds, boolean sent,
@@ -804,10 +789,15 @@ public class ConversationActivity extends BriarActivity
groupInvitationManager.respondToInvitation(contactId, id, accept); groupInvitationManager.respondToInvitation(contactId, id, accept);
} }
private ListenableFutureTask<String> getContactNameTask() { private void loadContactName() {
if (!contactNameTaskStarted.getAndSet(true)) runOnDbThread(() -> {
runOnDbThread(contactNameTask); try {
return contactNameTask; Contact c = contactManager.getContact(contactId);
contactName.postValue(c.getAuthor().getName());
} catch (DbException e) {
handleDbException(e);
}
});
} }
} }

View File

@@ -1,23 +0,0 @@
/**
* Copyright (C) 2014 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms.components.util;
public interface FutureTaskListener<V> {
void onSuccess(V result);
void onFailure(Throwable error);
}

View File

@@ -1,105 +0,0 @@
/*
* Copyright (C) 2014 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms.components.util;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import javax.annotation.Nullable;
public class ListenableFutureTask<V> extends FutureTask<V> {
private final List<FutureTaskListener<V>> listeners = new LinkedList<>();
@Nullable
private final Object identifier;
public ListenableFutureTask(Callable<V> callable) {
this(callable, null);
}
private ListenableFutureTask(Callable<V> callable,
@Nullable Object identifier) {
super(callable);
this.identifier = identifier;
}
public ListenableFutureTask(V result) {
this(result, null);
}
private ListenableFutureTask(V result, @Nullable Object identifier) {
super(() -> result);
this.identifier = identifier;
this.run();
}
public synchronized void addListener(FutureTaskListener<V> listener) {
if (this.isDone()) {
callback(listener);
} else {
this.listeners.add(listener);
}
}
public synchronized void removeListener(FutureTaskListener<V> listener) {
this.listeners.remove(listener);
}
@Override
protected synchronized void done() {
callback();
}
private void callback() {
for (FutureTaskListener<V> listener : listeners) {
callback(listener);
}
}
private void callback(FutureTaskListener<V> listener) {
if (listener != null) {
try {
listener.onSuccess(get());
} catch (InterruptedException e) {
throw new AssertionError(e);
} catch (ExecutionException e) {
listener.onFailure(e);
}
}
}
@Override
public boolean equals(Object other) {
if (other != null && other instanceof ListenableFutureTask &&
this.identifier != null) {
return identifier.equals(other);
} else {
return super.equals(other);
}
}
@Override
public int hashCode() {
if (identifier != null) return identifier.hashCode();
else return super.hashCode();
}
}