mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 21:59:54 +01:00
Access MessageTree only on UiThread and improve code in the process
This commit is contained in:
@@ -94,8 +94,9 @@ class ForumViewModel extends ThreadListViewModel<ForumPostItem> {
|
|||||||
ForumPostReceivedEvent f = (ForumPostReceivedEvent) e;
|
ForumPostReceivedEvent f = (ForumPostReceivedEvent) e;
|
||||||
if (f.getGroupId().equals(groupId)) {
|
if (f.getGroupId().equals(groupId)) {
|
||||||
LOG.info("Forum post received, adding...");
|
LOG.info("Forum post received, adding...");
|
||||||
ForumPostItem item = buildItem(f.getHeader(), f.getText());
|
ForumPostItem item =
|
||||||
addItem(item);
|
new ForumPostItem(f.getHeader(), f.getText());
|
||||||
|
addItem(item, false);
|
||||||
}
|
}
|
||||||
} else if (e instanceof ForumInvitationResponseReceivedEvent) {
|
} else if (e instanceof ForumInvitationResponseReceivedEvent) {
|
||||||
ForumInvitationResponseReceivedEvent f =
|
ForumInvitationResponseReceivedEvent f =
|
||||||
@@ -140,10 +141,23 @@ class ForumViewModel extends ThreadListViewModel<ForumPostItem> {
|
|||||||
List<ForumPostHeader> headers =
|
List<ForumPostHeader> headers =
|
||||||
forumManager.getPostHeaders(txn, groupId);
|
forumManager.getPostHeaders(txn, groupId);
|
||||||
logDuration(LOG, "Loading headers", start);
|
logDuration(LOG, "Loading headers", start);
|
||||||
return createItems(txn, headers, this::buildItem);
|
start = now();
|
||||||
|
List<ForumPostItem> items = new ArrayList<>();
|
||||||
|
for (ForumPostHeader header : headers) {
|
||||||
|
items.add(loadItem(txn, header));
|
||||||
|
}
|
||||||
|
logDuration(LOG, "Loading bodies and creating items", start);
|
||||||
|
return items;
|
||||||
}, this::setItems);
|
}, this::setItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ForumPostItem loadItem(Transaction txn, PostHeader header)
|
||||||
|
throws DbException {
|
||||||
|
if (!(header instanceof ForumPostHeader)) throw new AssertionError();
|
||||||
|
String text = forumManager.getPostText(txn, header.getId());
|
||||||
|
return new ForumPostItem((ForumPostHeader) header, text);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createAndStoreMessage(String text,
|
public void createAndStoreMessage(String text,
|
||||||
@Nullable MessageId parentId) {
|
@Nullable MessageId parentId) {
|
||||||
@@ -171,26 +185,15 @@ class ForumViewModel extends ThreadListViewModel<ForumPostItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void storePost(ForumPost msg, String text) {
|
private void storePost(ForumPost msg, String text) {
|
||||||
runOnDbThread(() -> {
|
runOnDbThread(false, txn -> {
|
||||||
try {
|
long start = now();
|
||||||
long start = now();
|
ForumPostHeader header = forumManager.addLocalPost(txn, msg);
|
||||||
ForumPostHeader header = forumManager.addLocalPost(msg);
|
logDuration(LOG, "Storing forum post", start);
|
||||||
addItemAsync(buildItem(header, text));
|
txn.attach(() -> {
|
||||||
logDuration(LOG, "Storing forum post", start);
|
ForumPostItem item = new ForumPostItem(header, text);
|
||||||
} catch (DbException e) {
|
addItem(item, true);
|
||||||
logException(LOG, WARNING, e);
|
});
|
||||||
}
|
}, e -> logException(LOG, WARNING, e));
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private ForumPostItem buildItem(ForumPostHeader header, String text) {
|
|
||||||
return new ForumPostItem(header, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String loadMessageText(Transaction txn, PostHeader header)
|
|
||||||
throws DbException {
|
|
||||||
return forumManager.getPostText(txn, header.getId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
|
|||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.client.MessageTracker;
|
import org.briarproject.briar.api.client.MessageTracker;
|
||||||
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
|
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
|
||||||
import org.briarproject.briar.api.client.PostHeader;
|
|
||||||
import org.briarproject.briar.api.privategroup.GroupMember;
|
import org.briarproject.briar.api.privategroup.GroupMember;
|
||||||
import org.briarproject.briar.api.privategroup.GroupMessage;
|
import org.briarproject.briar.api.privategroup.GroupMessage;
|
||||||
import org.briarproject.briar.api.privategroup.GroupMessageFactory;
|
import org.briarproject.briar.api.privategroup.GroupMessageFactory;
|
||||||
@@ -105,7 +104,7 @@ class GroupViewModel extends ThreadListViewModel<GroupMessageItem> {
|
|||||||
if (!g.isLocal() && g.getGroupId().equals(groupId)) {
|
if (!g.isLocal() && g.getGroupId().equals(groupId)) {
|
||||||
LOG.info("Group message received, adding...");
|
LOG.info("Group message received, adding...");
|
||||||
GroupMessageItem item = buildItem(g.getHeader(), g.getText());
|
GroupMessageItem item = buildItem(g.getHeader(), g.getText());
|
||||||
addItem(item);
|
addItem(item, false);
|
||||||
// In case the join message comes from the creator,
|
// In case the join message comes from the creator,
|
||||||
// we need to reload the sharing contacts
|
// we need to reload the sharing contacts
|
||||||
// in case it was delayed and the sharing count is wrong (#850).
|
// in case it was delayed and the sharing count is wrong (#850).
|
||||||
@@ -171,10 +170,28 @@ class GroupViewModel extends ThreadListViewModel<GroupMessageItem> {
|
|||||||
List<GroupMessageHeader> headers =
|
List<GroupMessageHeader> headers =
|
||||||
privateGroupManager.getHeaders(txn, groupId);
|
privateGroupManager.getHeaders(txn, groupId);
|
||||||
logDuration(LOG, "Loading headers", start);
|
logDuration(LOG, "Loading headers", start);
|
||||||
return createItems(txn, headers, this::buildItem);
|
start = now();
|
||||||
|
List<GroupMessageItem> items = new ArrayList<>();
|
||||||
|
for (GroupMessageHeader header : headers) {
|
||||||
|
items.add(loadItem(txn, header));
|
||||||
|
}
|
||||||
|
logDuration(LOG, "Loading bodies and creating items", start);
|
||||||
|
return items;
|
||||||
}, this::setItems);
|
}, this::setItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private GroupMessageItem loadItem(Transaction txn,
|
||||||
|
GroupMessageHeader header) throws DbException {
|
||||||
|
String text;
|
||||||
|
if (header instanceof JoinMessageHeader) {
|
||||||
|
// will be looked up later
|
||||||
|
text = "";
|
||||||
|
} else {
|
||||||
|
text = privateGroupManager.getMessageText(txn, header.getId());
|
||||||
|
}
|
||||||
|
return buildItem(header, text);
|
||||||
|
}
|
||||||
|
|
||||||
private GroupMessageItem buildItem(GroupMessageHeader header, String text) {
|
private GroupMessageItem buildItem(GroupMessageHeader header, String text) {
|
||||||
if (header instanceof JoinMessageHeader) {
|
if (header instanceof JoinMessageHeader) {
|
||||||
return new JoinMessageItem((JoinMessageHeader) header, text);
|
return new JoinMessageItem((JoinMessageHeader) header, text);
|
||||||
@@ -182,16 +199,6 @@ class GroupViewModel extends ThreadListViewModel<GroupMessageItem> {
|
|||||||
return new GroupMessageItem(header, text);
|
return new GroupMessageItem(header, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String loadMessageText(
|
|
||||||
Transaction txn, PostHeader header) throws DbException {
|
|
||||||
if (header instanceof JoinMessageHeader) {
|
|
||||||
// will be looked up later
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return privateGroupManager.getMessageText(txn, header.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createAndStoreMessage(String text,
|
public void createAndStoreMessage(String text,
|
||||||
@Nullable MessageId parentId) {
|
@Nullable MessageId parentId) {
|
||||||
@@ -222,17 +229,15 @@ class GroupViewModel extends ThreadListViewModel<GroupMessageItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void storePost(GroupMessage msg, String text) {
|
private void storePost(GroupMessage msg, String text) {
|
||||||
runOnDbThread(() -> {
|
runOnDbThread(false, txn -> {
|
||||||
try {
|
long start = now();
|
||||||
long start = now();
|
GroupMessageHeader header =
|
||||||
GroupMessageHeader header =
|
privateGroupManager.addLocalMessage(txn, msg);
|
||||||
privateGroupManager.addLocalMessage(msg);
|
logDuration(LOG, "Storing group message", start);
|
||||||
addItemAsync(buildItem(header, text));
|
txn.attach(() ->
|
||||||
logDuration(LOG, "Storing group message", start);
|
addItem(buildItem(header, text), true)
|
||||||
} catch (DbException e) {
|
);
|
||||||
logException(LOG, WARNING, e);
|
}, e -> logException(LOG, WARNING, e));
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import android.app.Application;
|
|||||||
import org.briarproject.bramble.api.crypto.CryptoExecutor;
|
import org.briarproject.bramble.api.crypto.CryptoExecutor;
|
||||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
|
||||||
import org.briarproject.bramble.api.db.TransactionManager;
|
import org.briarproject.bramble.api.db.TransactionManager;
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
@@ -26,11 +25,8 @@ import org.briarproject.briar.android.viewmodel.LiveResult;
|
|||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.client.MessageTracker;
|
import org.briarproject.briar.api.client.MessageTracker;
|
||||||
import org.briarproject.briar.api.client.MessageTree;
|
import org.briarproject.briar.api.client.MessageTree;
|
||||||
import org.briarproject.briar.api.client.PostHeader;
|
|
||||||
import org.briarproject.briar.client.MessageTreeImpl;
|
import org.briarproject.briar.client.MessageTreeImpl;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
@@ -46,9 +42,7 @@ import androidx.lifecycle.MutableLiveData;
|
|||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
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;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -67,6 +61,7 @@ public abstract class ThreadListViewModel<I extends ThreadItem>
|
|||||||
private final MessageTracker messageTracker;
|
private final MessageTracker messageTracker;
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
|
|
||||||
|
// UIThread
|
||||||
private final MessageTree<I> messageTree = new MessageTreeImpl<>();
|
private final MessageTree<I> messageTree = new MessageTreeImpl<>();
|
||||||
private final MutableLiveData<LiveResult<List<I>>> items =
|
private final MutableLiveData<LiveResult<List<I>>> items =
|
||||||
new MutableLiveData<>();
|
new MutableLiveData<>();
|
||||||
@@ -175,55 +170,34 @@ public abstract class ThreadListViewModel<I extends ThreadItem>
|
|||||||
* Loads the ContactIds of all contacts the group is shared with
|
* Loads the ContactIds of all contacts the group is shared with
|
||||||
* and adds them to {@link SharingController}.
|
* and adds them to {@link SharingController}.
|
||||||
*/
|
*/
|
||||||
public abstract void loadSharingContacts();
|
protected abstract void loadSharingContacts();
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
protected void setItems(LiveResult<List<I>> items) {
|
protected void setItems(LiveResult<List<I>> items) {
|
||||||
this.items.setValue(items);
|
if (items.hasError()) {
|
||||||
}
|
this.items.setValue(items);
|
||||||
|
} else {
|
||||||
@DatabaseExecutor
|
messageTree.clear();
|
||||||
protected <H extends PostHeader> List<I> createItems(
|
// not null, because hasError() is false
|
||||||
Transaction txn, Collection<H> headers, ItemGetter<H, I> itemGetter)
|
messageTree.add(items.getResultOrNull());
|
||||||
throws DbException {
|
LiveResult<List<I>> result =
|
||||||
long start = now();
|
new LiveResult<>(messageTree.depthFirstOrder());
|
||||||
List<I> items = new ArrayList<>();
|
this.items.setValue(result);
|
||||||
for (H header : headers) {
|
|
||||||
String text = loadMessageText(txn, header);
|
|
||||||
items.add(itemGetter.getItem(header, text));
|
|
||||||
}
|
}
|
||||||
logDuration(LOG, "Loading bodies and creating items", start);
|
|
||||||
|
|
||||||
messageTree.clear();
|
|
||||||
messageTree.add(items);
|
|
||||||
return messageTree.depthFirstOrder();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a remote item on the UI thread.
|
* Add a remote item on the UI thread.
|
||||||
* The list will not scroll, but show an unread indicator.
|
*
|
||||||
|
* @param scrollToItem whether the list will scroll to the newly added item
|
||||||
*/
|
*/
|
||||||
@UiThread
|
@UiThread
|
||||||
protected void addItem(I item) {
|
protected void addItem(I item, boolean scrollToItem) {
|
||||||
messageTree.add(item);
|
messageTree.add(item);
|
||||||
|
if (scrollToItem) this.scrollToItem.set(item.getId());
|
||||||
items.setValue(new LiveResult<>(messageTree.depthFirstOrder()));
|
items.setValue(new LiveResult<>(messageTree.depthFirstOrder()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a local item from the DB thread.
|
|
||||||
* The list will scroll to the new item.
|
|
||||||
*/
|
|
||||||
@DatabaseExecutor
|
|
||||||
protected void addItemAsync(I item) {
|
|
||||||
messageTree.add(item);
|
|
||||||
scrollToItem.set(item.getId());
|
|
||||||
items.postValue(new LiveResult<>(messageTree.depthFirstOrder()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@DatabaseExecutor
|
|
||||||
protected abstract String loadMessageText(Transaction txn,
|
|
||||||
PostHeader header) throws DbException;
|
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
void setReplyId(@Nullable MessageId id) {
|
void setReplyId(@Nullable MessageId id) {
|
||||||
replyId = id;
|
replyId = id;
|
||||||
@@ -271,8 +245,4 @@ public abstract class ThreadListViewModel<I extends ThreadItem>
|
|||||||
return scrollToItem.getAndSet(null);
|
return scrollToItem.getAndSet(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ItemGetter<H extends PostHeader, I> {
|
|
||||||
I getItem(H header, String text);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user