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;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.Observer;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.design.widget.Snackbar;
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.event.PrivateMessageReceivedEvent;
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.Collection;
@@ -81,13 +82,10 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
import de.hdodenhof.circleimageview.CircleImageView;
@@ -141,18 +139,6 @@ public class ConversationActivity extends BriarActivity
private BriarRecyclerView list;
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
@Inject
volatile ContactManager contactManager;
@@ -177,11 +163,10 @@ public class ConversationActivity extends BriarActivity
private volatile ContactId contactId;
@Nullable
private volatile String contactName;
@Nullable
private volatile AuthorId contactAuthorId;
@Nullable
private volatile GroupId messagingGroupId;
private MutableLiveData<String> contactName = new MutableLiveData<>();
@SuppressWarnings("ConstantConditions")
@Override
@@ -292,7 +277,7 @@ public class ConversationActivity extends BriarActivity
long start = now();
if (contactName == null || contactAuthorId == null) {
Contact contact = contactManager.getContact(contactId);
contactName = contact.getAuthor().getName();
contactName.postValue(contact.getAuthor().getName());
contactAuthorId = contact.getAuthor().getId();
}
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() {
runOnUiThreadUnlessDestroyed(() -> {
//noinspection ConstantConditions
toolbarAvatar.setImageDrawable(
new IdenticonDrawable(contactAuthorId.getBytes()));
toolbarTitle.setText(contactName);
toolbarTitle.setText(contactName.getValue());
});
}
@@ -381,13 +367,13 @@ public class ConversationActivity extends BriarActivity
ConversationItem item;
if (h instanceof IntroductionResponse) {
IntroductionResponse i = (IntroductionResponse) h;
item = ConversationItem.from(this, contactName, i);
item = ConversationItem.from(this, contactName.getValue(), i);
} else if (h instanceof PrivateRequest) {
PrivateRequest r = (PrivateRequest) h;
item = ConversationItem.from(this, contactName, r);
item = ConversationItem.from(this, contactName.getValue(), r);
} else if (h instanceof PrivateResponse) {
PrivateResponse r = (PrivateResponse) h;
item = ConversationItem.from(this, contactName, r);
item = ConversationItem.from(this, contactName.getValue(), r);
} else {
item = ConversationItem.from(h);
String body = bodyCache.get(h.getId());
@@ -480,43 +466,42 @@ public class ConversationActivity extends BriarActivity
}
private void onNewPrivateMessage(PrivateMessageHeader h) {
if (h instanceof PrivateRequest || h instanceof PrivateResponse) {
getContactNameTask().addListener(new FutureTaskListener<String>() {
@Override
public void onSuccess(String contactName) {
runOnUiThreadUnlessDestroyed(
() -> handlePrivateRequestAndResponse(h,
contactName));
}
@Override
public void onFailure(Throwable exception) {
runOnUiThreadUnlessDestroyed(
() -> handleDbException((DbException) exception));
}
});
} else {
addConversationItem(ConversationItem.from(h));
loadMessageBody(h.getId());
}
}
@UiThread
private void handlePrivateRequestAndResponse(PrivateMessageHeader h,
String contactName) {
ConversationItem item;
if (h instanceof PrivateRequest) {
PrivateRequest m = (PrivateRequest) h;
item = ConversationItem
.from(ConversationActivity.this, contactName, m);
} else if (h instanceof PrivateResponse) {
PrivateResponse m = (PrivateResponse) h;
item = ConversationItem
.from(ConversationActivity.this, contactName, m);
} else {
throw new AssertionError("Unknown PrivateMessageHeader");
}
addConversationItem(item);
runOnUiThreadUnlessDestroyed(() -> {
if (h instanceof PrivateRequest) {
contactName.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String name) {
if (name == null) loadContactName();
else {
PrivateRequest m = (PrivateRequest) h;
ConversationItem item = ConversationItem.from(
ConversationActivity.this, name, m);
addConversationItem(item);
contactName.removeObserver(this);
}
}
});
if (contactName.getValue() == null) loadContactName();
} else if (h instanceof PrivateResponse) {
contactName.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String name) {
if (name == null) loadContactName();
else {
PrivateResponse m = (PrivateResponse) h;
ConversationItem item = ConversationItem.from(
ConversationActivity.this, name, m);
addConversationItem(item);
contactName.removeObserver(this);
}
}
});
if (contactName.getValue() == null) loadContactName();
} else {
addConversationItem(ConversationItem.from(h));
loadMessageBody(h.getId());
}
});
}
private void markMessages(Collection<MessageId> messageIds, boolean sent,
@@ -804,10 +789,15 @@ public class ConversationActivity extends BriarActivity
groupInvitationManager.respondToInvitation(contactId, id, accept);
}
private ListenableFutureTask<String> getContactNameTask() {
if (!contactNameTaskStarted.getAndSet(true))
runOnDbThread(contactNameTask);
return contactNameTask;
private void loadContactName() {
runOnDbThread(() -> {
try {
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();
}
}