mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 05:09:53 +01:00
Avoid race conditions when updating the UI from events.
This commit is contained in:
@@ -32,6 +32,7 @@ import org.briarproject.api.identity.Author;
|
|||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@@ -51,6 +52,7 @@ public class BlogFragment extends BaseFragment implements
|
|||||||
OnBlogPostAddedListener {
|
OnBlogPostAddedListener {
|
||||||
|
|
||||||
public final static String TAG = BlogFragment.class.getName();
|
public final static String TAG = BlogFragment.class.getName();
|
||||||
|
private static final Logger LOG = Logger.getLogger(TAG);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
BlogController blogController;
|
BlogController blogController;
|
||||||
@@ -207,6 +209,7 @@ public class BlogFragment extends BaseFragment implements
|
|||||||
listener) {
|
listener) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(BlogPostItem post) {
|
public void onResultUi(BlogPostItem post) {
|
||||||
|
adapter.incrementRevision();
|
||||||
adapter.add(post);
|
adapter.add(post);
|
||||||
if (local) {
|
if (local) {
|
||||||
list.scrollToPosition(0);
|
list.scrollToPosition(0);
|
||||||
@@ -228,16 +231,23 @@ public class BlogFragment extends BaseFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
void loadBlogPosts(final boolean reload) {
|
void loadBlogPosts(final boolean reload) {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
blogController.loadBlogPosts(
|
blogController.loadBlogPosts(
|
||||||
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
||||||
listener) {
|
listener) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(Collection<BlogPostItem> posts) {
|
public void onResultUi(Collection<BlogPostItem> posts) {
|
||||||
if (posts.isEmpty()) {
|
if (revision == adapter.getRevision()) {
|
||||||
list.showData();
|
adapter.incrementRevision();
|
||||||
|
if (posts.isEmpty()) {
|
||||||
|
list.showData();
|
||||||
|
} else {
|
||||||
|
adapter.addAll(posts);
|
||||||
|
if (reload) list.scrollToPosition(0);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
adapter.addAll(posts);
|
LOG.info("Concurrent update, reloading");
|
||||||
if (reload) list.scrollToPosition(0);
|
loadBlogPosts(reload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import org.briarproject.api.blogs.BlogPostHeader;
|
|||||||
import org.briarproject.api.db.DbException;
|
import org.briarproject.api.db.DbException;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@@ -41,6 +42,7 @@ public class FeedFragment extends BaseFragment implements
|
|||||||
OnBlogPostClickListener, OnBlogPostAddedListener {
|
OnBlogPostClickListener, OnBlogPostAddedListener {
|
||||||
|
|
||||||
public final static String TAG = FeedFragment.class.getName();
|
public final static String TAG = FeedFragment.class.getName();
|
||||||
|
private static final Logger LOG = Logger.getLogger(TAG);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
FeedController feedController;
|
FeedController feedController;
|
||||||
@@ -129,14 +131,21 @@ public class FeedFragment extends BaseFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadBlogPosts(final boolean clear) {
|
private void loadBlogPosts(final boolean clear) {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
feedController.loadBlogPosts(
|
feedController.loadBlogPosts(
|
||||||
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
||||||
listener) {
|
listener) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(Collection<BlogPostItem> posts) {
|
public void onResultUi(Collection<BlogPostItem> posts) {
|
||||||
if (clear) adapter.setItems(posts);
|
if (revision == adapter.getRevision()) {
|
||||||
else adapter.addAll(posts);
|
adapter.incrementRevision();
|
||||||
if (posts.isEmpty()) list.showData();
|
if (clear) adapter.setItems(posts);
|
||||||
|
else adapter.addAll(posts);
|
||||||
|
if (posts.isEmpty()) list.showData();
|
||||||
|
} else {
|
||||||
|
LOG.info("Concurrent update, reloading");
|
||||||
|
loadBlogPosts(clear);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -193,6 +202,7 @@ public class FeedFragment extends BaseFragment implements
|
|||||||
listener) {
|
listener) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(BlogPostItem post) {
|
public void onResultUi(BlogPostItem post) {
|
||||||
|
adapter.incrementRevision();
|
||||||
adapter.add(post);
|
adapter.add(post);
|
||||||
if (local) {
|
if (local) {
|
||||||
showSnackBar(R.string.blogs_blog_post_created);
|
showSnackBar(R.string.blogs_blog_post_created);
|
||||||
|
|||||||
@@ -125,27 +125,43 @@ public class RssFeedManageActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadFeeds() {
|
private void loadFeeds() {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
addFeeds(feedManager.getFeeds());
|
displayFeeds(revision, feedManager.getFeeds());
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
list.setEmptyText(R.string.blogs_rss_feeds_manage_error);
|
onLoadError();
|
||||||
list.showData();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addFeeds(final List<Feed> feeds) {
|
private void displayFeeds(final int revision, final List<Feed> feeds) {
|
||||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (feeds.isEmpty()) list.showData();
|
if (revision == adapter.getRevision()) {
|
||||||
else adapter.addAll(feeds);
|
adapter.incrementRevision();
|
||||||
|
if (feeds.isEmpty()) list.showData();
|
||||||
|
else adapter.addAll(feeds);
|
||||||
|
} else {
|
||||||
|
LOG.info("Concurrent update, reloading");
|
||||||
|
loadFeeds();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onLoadError() {
|
||||||
|
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
list.setEmptyText(R.string.blogs_rss_feeds_manage_error);
|
||||||
|
list.showData();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -154,6 +170,7 @@ public class RssFeedManageActivity extends BriarActivity
|
|||||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
adapter.incrementRevision();
|
||||||
adapter.remove(feed);
|
adapter.remove(feed);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -190,6 +190,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadContacts() {
|
private void loadContacts() {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
listener.runOnDbThread(new Runnable() {
|
listener.runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -216,7 +217,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Full load took " + duration + " ms");
|
LOG.info("Full load took " + duration + " ms");
|
||||||
displayContacts(contacts);
|
displayContacts(revision, contacts);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
@@ -225,12 +226,19 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayContacts(final List<ContactListItem> contacts) {
|
private void displayContacts(final int revision,
|
||||||
|
final List<ContactListItem> contacts) {
|
||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (contacts.isEmpty()) list.showData();
|
if (revision == adapter.getRevision()) {
|
||||||
else adapter.addAll(contacts);
|
adapter.incrementRevision();
|
||||||
|
if (contacts.isEmpty()) list.showData();
|
||||||
|
else adapter.addAll(contacts);
|
||||||
|
} else {
|
||||||
|
LOG.info("Concurrent update, reloading");
|
||||||
|
loadContacts();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -288,6 +296,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
adapter.incrementRevision();
|
||||||
int position = adapter.findItemPosition(c);
|
int position = adapter.findItemPosition(c);
|
||||||
ContactListItem item = adapter.getItemAt(position);
|
ContactListItem item = adapter.getItemAt(position);
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
@@ -302,6 +311,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
adapter.incrementRevision();
|
||||||
int position = adapter.findItemPosition(c);
|
int position = adapter.findItemPosition(c);
|
||||||
ContactListItem item = adapter.getItemAt(position);
|
ContactListItem item = adapter.getItemAt(position);
|
||||||
if (item != null) adapter.remove(item);
|
if (item != null) adapter.remove(item);
|
||||||
@@ -313,6 +323,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
adapter.incrementRevision();
|
||||||
int position = adapter.findItemPosition(c);
|
int position = adapter.findItemPosition(c);
|
||||||
ContactListItem item = adapter.getItemAt(position);
|
ContactListItem item = adapter.getItemAt(position);
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
|
|||||||
@@ -289,12 +289,10 @@ public class ConversationActivity extends BriarActivity
|
|||||||
contactIdenticonKey =
|
contactIdenticonKey =
|
||||||
contact.getAuthor().getId().getBytes();
|
contact.getAuthor().getId().getBytes();
|
||||||
}
|
}
|
||||||
boolean connected =
|
|
||||||
connectionRegistry.isConnected(contactId);
|
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Loading contact took " + duration + " ms");
|
LOG.info("Loading contact took " + duration + " ms");
|
||||||
displayContactDetails(connected);
|
displayContactDetails();
|
||||||
} catch (NoSuchContactException e) {
|
} catch (NoSuchContactException e) {
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
@@ -305,7 +303,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayContactDetails(final boolean connected) {
|
private void displayContactDetails() {
|
||||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -313,7 +311,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
new IdenticonDrawable(contactIdenticonKey));
|
new IdenticonDrawable(contactIdenticonKey));
|
||||||
toolbarTitle.setText(contactName);
|
toolbarTitle.setText(contactName);
|
||||||
|
|
||||||
if (connected) {
|
if (connectionRegistry.isConnected(contactId)) {
|
||||||
toolbarStatus.setImageDrawable(ContextCompat
|
toolbarStatus.setImageDrawable(ContextCompat
|
||||||
.getDrawable(ConversationActivity.this,
|
.getDrawable(ConversationActivity.this,
|
||||||
R.drawable.contact_online));
|
R.drawable.contact_online));
|
||||||
@@ -332,6 +330,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadMessages() {
|
private void loadMessages() {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -357,7 +356,8 @@ public class ConversationActivity extends BriarActivity
|
|||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Loading messages took " + duration + " ms");
|
LOG.info("Loading messages took " + duration + " ms");
|
||||||
displayMessages(headers, introductions, invitations);
|
displayMessages(revision, headers, introductions,
|
||||||
|
invitations);
|
||||||
} catch (NoSuchContactException e) {
|
} catch (NoSuchContactException e) {
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
@@ -368,56 +368,66 @@ public class ConversationActivity extends BriarActivity
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayMessages(final Collection<PrivateMessageHeader> headers,
|
private void displayMessages(final int revision,
|
||||||
|
final Collection<PrivateMessageHeader> headers,
|
||||||
final Collection<IntroductionMessage> introductions,
|
final Collection<IntroductionMessage> introductions,
|
||||||
final Collection<InvitationMessage> invitations) {
|
final Collection<InvitationMessage> invitations) {
|
||||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
textInputView.setSendButtonEnabled(true);
|
if (revision == adapter.getRevision()) {
|
||||||
int size = headers.size() + introductions.size() +
|
adapter.incrementRevision();
|
||||||
invitations.size();
|
textInputView.setSendButtonEnabled(true);
|
||||||
if (size == 0) {
|
List<ConversationItem> items = createItems(headers,
|
||||||
list.showData();
|
introductions, invitations);
|
||||||
} else {
|
if (items.isEmpty()) list.showData();
|
||||||
List<ConversationItem> items = new ArrayList<>(size);
|
else adapter.addAll(items);
|
||||||
for (PrivateMessageHeader h : headers) {
|
|
||||||
ConversationMessageItem item = ConversationItem.from(h);
|
|
||||||
byte[] body = bodyCache.get(h.getId());
|
|
||||||
if (body == null) loadMessageBody(h.getId());
|
|
||||||
else item.setBody(body);
|
|
||||||
items.add(item);
|
|
||||||
}
|
|
||||||
for (IntroductionMessage im : introductions) {
|
|
||||||
if (im instanceof IntroductionRequest) {
|
|
||||||
IntroductionRequest ir = (IntroductionRequest) im;
|
|
||||||
items.add(ConversationItem.from(ir));
|
|
||||||
} else {
|
|
||||||
IntroductionResponse ir = (IntroductionResponse) im;
|
|
||||||
items.add(ConversationItem
|
|
||||||
.from(ConversationActivity.this,
|
|
||||||
contactName, ir));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (InvitationMessage im : invitations) {
|
|
||||||
if (im instanceof InvitationRequest) {
|
|
||||||
InvitationRequest ir = (InvitationRequest) im;
|
|
||||||
items.add(ConversationItem.from(ir));
|
|
||||||
} else if (im instanceof InvitationResponse) {
|
|
||||||
InvitationResponse ir = (InvitationResponse) im;
|
|
||||||
items.add(ConversationItem
|
|
||||||
.from(ConversationActivity.this,
|
|
||||||
contactName, ir));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
adapter.addAll(items);
|
|
||||||
// Scroll to the bottom
|
// Scroll to the bottom
|
||||||
list.scrollToPosition(adapter.getItemCount() - 1);
|
list.scrollToPosition(adapter.getItemCount() - 1);
|
||||||
|
} else {
|
||||||
|
LOG.info("Concurrent update, reloading");
|
||||||
|
loadMessages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<ConversationItem> createItems(
|
||||||
|
Collection<PrivateMessageHeader> headers,
|
||||||
|
Collection<IntroductionMessage> introductions,
|
||||||
|
Collection<InvitationMessage> invitations) {
|
||||||
|
int size = headers.size() + introductions.size() + invitations.size();
|
||||||
|
List<ConversationItem> items = new ArrayList<>(size);
|
||||||
|
for (PrivateMessageHeader h : headers) {
|
||||||
|
ConversationMessageItem item = ConversationItem.from(h);
|
||||||
|
byte[] body = bodyCache.get(h.getId());
|
||||||
|
if (body == null) loadMessageBody(h.getId());
|
||||||
|
else item.setBody(body);
|
||||||
|
items.add(item);
|
||||||
|
}
|
||||||
|
for (IntroductionMessage im : introductions) {
|
||||||
|
if (im instanceof IntroductionRequest) {
|
||||||
|
IntroductionRequest ir = (IntroductionRequest) im;
|
||||||
|
items.add(ConversationItem.from(ir));
|
||||||
|
} else {
|
||||||
|
IntroductionResponse ir = (IntroductionResponse) im;
|
||||||
|
items.add(ConversationItem.from(ConversationActivity.this,
|
||||||
|
contactName, ir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (InvitationMessage im : invitations) {
|
||||||
|
if (im instanceof InvitationRequest) {
|
||||||
|
InvitationRequest ir = (InvitationRequest) im;
|
||||||
|
items.add(ConversationItem.from(ir));
|
||||||
|
} else if (im instanceof InvitationResponse) {
|
||||||
|
InvitationResponse ir = (InvitationResponse) im;
|
||||||
|
items.add(ConversationItem.from(ConversationActivity.this,
|
||||||
|
contactName, ir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
private void loadMessageBody(final MessageId m) {
|
private void loadMessageBody(final MessageId m) {
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@@ -461,6 +471,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
adapter.incrementRevision();
|
||||||
adapter.add(item);
|
adapter.add(item);
|
||||||
// Scroll to the bottom
|
// Scroll to the bottom
|
||||||
list.scrollToPosition(adapter.getItemCount() - 1);
|
list.scrollToPosition(adapter.getItemCount() - 1);
|
||||||
@@ -535,13 +546,13 @@ public class ConversationActivity extends BriarActivity
|
|||||||
ContactConnectedEvent c = (ContactConnectedEvent) e;
|
ContactConnectedEvent c = (ContactConnectedEvent) e;
|
||||||
if (c.getContactId().equals(contactId)) {
|
if (c.getContactId().equals(contactId)) {
|
||||||
LOG.info("Contact connected");
|
LOG.info("Contact connected");
|
||||||
displayContactDetails(true);
|
displayContactDetails();
|
||||||
}
|
}
|
||||||
} else if (e instanceof ContactDisconnectedEvent) {
|
} else if (e instanceof ContactDisconnectedEvent) {
|
||||||
ContactDisconnectedEvent c = (ContactDisconnectedEvent) e;
|
ContactDisconnectedEvent c = (ContactDisconnectedEvent) e;
|
||||||
if (c.getContactId().equals(contactId)) {
|
if (c.getContactId().equals(contactId)) {
|
||||||
LOG.info("Contact disconnected");
|
LOG.info("Contact disconnected");
|
||||||
displayContactDetails(false);
|
displayContactDetails();
|
||||||
}
|
}
|
||||||
} else if (e instanceof IntroductionRequestReceivedEvent) {
|
} else if (e instanceof IntroductionRequestReceivedEvent) {
|
||||||
IntroductionRequestReceivedEvent event =
|
IntroductionRequestReceivedEvent event =
|
||||||
@@ -589,6 +600,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
adapter.incrementRevision();
|
||||||
Set<MessageId> messages = new HashSet<>(messageIds);
|
Set<MessageId> messages = new HashSet<>(messageIds);
|
||||||
SparseArray<OutgoingItem> list = adapter.getOutgoingMessages();
|
SparseArray<OutgoingItem> list = adapter.getOutgoingMessages();
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (int i = 0; i < list.size(); i++) {
|
||||||
@@ -807,13 +819,11 @@ public class ConversationActivity extends BriarActivity
|
|||||||
timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
|
timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
|
||||||
try {
|
try {
|
||||||
if (accept) {
|
if (accept) {
|
||||||
introductionManager
|
introductionManager.acceptIntroduction(contactId,
|
||||||
.acceptIntroduction(contactId, sessionId,
|
sessionId, timestamp);
|
||||||
timestamp);
|
|
||||||
} else {
|
} else {
|
||||||
introductionManager
|
introductionManager.declineIntroduction(contactId,
|
||||||
.declineIntroduction(contactId, sessionId,
|
sessionId, timestamp);
|
||||||
timestamp);
|
|
||||||
}
|
}
|
||||||
loadMessages();
|
loadMessages();
|
||||||
} catch (DbException | FormatException e) {
|
} catch (DbException | FormatException e) {
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ public class ForumActivity extends
|
|||||||
private void showUnsubscribeDialog() {
|
private void showUnsubscribeDialog() {
|
||||||
OnClickListener okListener = new OnClickListener() {
|
OnClickListener okListener = new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(final DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
deleteNamedGroup();
|
deleteNamedGroup();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -162,8 +162,7 @@ public class ForumActivity extends
|
|||||||
|
|
||||||
private void deleteNamedGroup() {
|
private void deleteNamedGroup() {
|
||||||
forumController.deleteNamedGroup(
|
forumController.deleteNamedGroup(
|
||||||
new UiResultExceptionHandler<Void, DbException>(
|
new UiResultExceptionHandler<Void, DbException>(this) {
|
||||||
ForumActivity.this) {
|
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(Void v) {
|
public void onResultUi(Void v) {
|
||||||
Toast.makeText(ForumActivity.this,
|
Toast.makeText(ForumActivity.this,
|
||||||
|
|||||||
@@ -150,6 +150,7 @@ public class ForumListFragment extends BaseEventFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadForums() {
|
private void loadForums() {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
listener.runOnDbThread(new Runnable() {
|
listener.runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -168,7 +169,7 @@ public class ForumListFragment extends BaseEventFragment implements
|
|||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Full load took " + duration + " ms");
|
LOG.info("Full load took " + duration + " ms");
|
||||||
displayForums(forums);
|
displayForums(revision, forums);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
@@ -177,12 +178,19 @@ public class ForumListFragment extends BaseEventFragment implements
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayForums(final Collection<ForumListItem> forums) {
|
private void displayForums(final int revision,
|
||||||
|
final Collection<ForumListItem> forums) {
|
||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (forums.isEmpty()) list.showData();
|
if (revision == adapter.getRevision()) {
|
||||||
else adapter.addAll(forums);
|
adapter.incrementRevision();
|
||||||
|
if (forums.isEmpty()) list.showData();
|
||||||
|
else adapter.addAll(forums);
|
||||||
|
} else {
|
||||||
|
LOG.info("Concurrent update, reloading");
|
||||||
|
loadForums();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -254,6 +262,7 @@ public class ForumListFragment extends BaseEventFragment implements
|
|||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
adapter.incrementRevision();
|
||||||
int position = adapter.findItemPosition(g);
|
int position = adapter.findItemPosition(g);
|
||||||
ForumListItem item = adapter.getItemAt(position);
|
ForumListItem item = adapter.getItemAt(position);
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
@@ -268,6 +277,7 @@ public class ForumListFragment extends BaseEventFragment implements
|
|||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
adapter.incrementRevision();
|
||||||
int position = adapter.findItemPosition(g);
|
int position = adapter.findItemPosition(g);
|
||||||
ForumListItem item = adapter.getItemAt(position);
|
ForumListItem item = adapter.getItemAt(position);
|
||||||
if (item != null) adapter.remove(item);
|
if (item != null) adapter.remove(item);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import org.briarproject.api.privategroup.GroupMessageHeader;
|
|||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@@ -30,6 +31,7 @@ public class GroupListFragment extends BaseFragment implements
|
|||||||
GroupListListener, OnGroupRemoveClickListener {
|
GroupListListener, OnGroupRemoveClickListener {
|
||||||
|
|
||||||
public final static String TAG = GroupListFragment.class.getName();
|
public final static String TAG = GroupListFragment.class.getName();
|
||||||
|
private static final Logger LOG = Logger.getLogger(TAG);
|
||||||
|
|
||||||
public static GroupListFragment newInstance() {
|
public static GroupListFragment newInstance() {
|
||||||
return new GroupListFragment();
|
return new GroupListFragment();
|
||||||
@@ -120,6 +122,7 @@ public class GroupListFragment extends BaseFragment implements
|
|||||||
@UiThread
|
@UiThread
|
||||||
@Override
|
@Override
|
||||||
public void onGroupMessageAdded(GroupMessageHeader header) {
|
public void onGroupMessageAdded(GroupMessageHeader header) {
|
||||||
|
adapter.incrementRevision();
|
||||||
int position = adapter.findItemPosition(header.getGroupId());
|
int position = adapter.findItemPosition(header.getGroupId());
|
||||||
GroupItem item = adapter.getItemAt(position);
|
GroupItem item = adapter.getItemAt(position);
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
@@ -137,6 +140,7 @@ public class GroupListFragment extends BaseFragment implements
|
|||||||
@UiThread
|
@UiThread
|
||||||
@Override
|
@Override
|
||||||
public void onGroupRemoved(GroupId groupId) {
|
public void onGroupRemoved(GroupId groupId) {
|
||||||
|
adapter.incrementRevision();
|
||||||
adapter.removeItem(groupId);
|
adapter.removeItem(groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,13 +150,20 @@ public class GroupListFragment extends BaseFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadGroups() {
|
private void loadGroups() {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
controller.loadGroups(
|
controller.loadGroups(
|
||||||
new UiResultExceptionHandler<Collection<GroupItem>, DbException>(
|
new UiResultExceptionHandler<Collection<GroupItem>, DbException>(
|
||||||
listener) {
|
listener) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(Collection<GroupItem> groups) {
|
public void onResultUi(Collection<GroupItem> groups) {
|
||||||
if (groups.isEmpty()) list.showData();
|
if (revision == adapter.getRevision()) {
|
||||||
else adapter.addAll(groups);
|
adapter.incrementRevision();
|
||||||
|
if (groups.isEmpty()) list.showData();
|
||||||
|
else adapter.addAll(groups);
|
||||||
|
} else {
|
||||||
|
LOG.info("Concurrent update, reloading");
|
||||||
|
loadGroups();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ abstract class InvitationsActivity extends BriarActivity
|
|||||||
protected static final Logger LOG =
|
protected static final Logger LOG =
|
||||||
Logger.getLogger(InvitationsActivity.class.getName());
|
Logger.getLogger(InvitationsActivity.class.getName());
|
||||||
|
|
||||||
private InvitationAdapter adapter;
|
protected InvitationAdapter adapter;
|
||||||
private BriarRecyclerView list;
|
private BriarRecyclerView list;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -84,6 +84,7 @@ abstract class InvitationsActivity extends BriarActivity
|
|||||||
Toast.makeText(this, res, LENGTH_SHORT).show();
|
Toast.makeText(this, res, LENGTH_SHORT).show();
|
||||||
|
|
||||||
// remove item and finish if it was the last
|
// remove item and finish if it was the last
|
||||||
|
adapter.incrementRevision();
|
||||||
adapter.remove(item);
|
adapter.remove(item);
|
||||||
if (adapter.getItemCount() == 0) {
|
if (adapter.getItemCount() == 0) {
|
||||||
supportFinishAfterTransition();
|
supportFinishAfterTransition();
|
||||||
@@ -102,7 +103,7 @@ abstract class InvitationsActivity extends BriarActivity
|
|||||||
|
|
||||||
abstract protected int getDeclineRes();
|
abstract protected int getDeclineRes();
|
||||||
|
|
||||||
protected void displayInvitations(
|
protected void displayInvitations(final int revision,
|
||||||
final Collection<InvitationItem> invitations, final boolean clear) {
|
final Collection<InvitationItem> invitations, final boolean clear) {
|
||||||
runOnUiThreadUnlessDestroyed(new Runnable() {
|
runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@@ -110,9 +111,13 @@ abstract class InvitationsActivity extends BriarActivity
|
|||||||
if (invitations.isEmpty()) {
|
if (invitations.isEmpty()) {
|
||||||
LOG.info("No more invitations available, finishing");
|
LOG.info("No more invitations available, finishing");
|
||||||
finish();
|
finish();
|
||||||
} else {
|
} else if (revision == adapter.getRevision()) {
|
||||||
|
adapter.incrementRevision();
|
||||||
if (clear) adapter.setItems(invitations);
|
if (clear) adapter.setItems(invitations);
|
||||||
else adapter.addAll(invitations);
|
else adapter.addAll(invitations);
|
||||||
|
} else {
|
||||||
|
LOG.info("Concurrent update, reloading");
|
||||||
|
loadInvitations(clear);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ public class InvitationsBlogActivity extends InvitationsActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void loadInvitations(final boolean clear) {
|
protected void loadInvitations(final boolean clear) {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -80,7 +81,7 @@ public class InvitationsBlogActivity extends InvitationsActivity {
|
|||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Load took " + duration + " ms");
|
LOG.info("Load took " + duration + " ms");
|
||||||
displayInvitations(invitations, clear);
|
displayInvitations(revision, invitations, clear);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ public class InvitationsForumActivity extends InvitationsActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void loadInvitations(final boolean clear) {
|
protected void loadInvitations(final boolean clear) {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -80,7 +81,7 @@ public class InvitationsForumActivity extends InvitationsActivity {
|
|||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Load took " + duration + " ms");
|
LOG.info("Load took " + duration + " ms");
|
||||||
displayInvitations(invitations, clear);
|
displayInvitations(revision, invitations, clear);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
|||||||
@@ -24,13 +24,15 @@ public abstract class ThreadItemAdapter<I extends ThreadItem>
|
|||||||
|
|
||||||
private final NestedTreeList<I> items = new NestedTreeList<>();
|
private final NestedTreeList<I> items = new NestedTreeList<>();
|
||||||
private final Map<I, ValueAnimator> animatingItems = new HashMap<>();
|
private final Map<I, ValueAnimator> animatingItems = new HashMap<>();
|
||||||
|
private final ThreadItemListener<I> listener;
|
||||||
|
private final LinearLayoutManager layoutManager;
|
||||||
|
|
||||||
// highlight not dependant on time
|
// highlight not dependant on time
|
||||||
private I replyItem;
|
private I replyItem;
|
||||||
// temporary highlight
|
// temporary highlight
|
||||||
private I addedItem;
|
private I addedItem;
|
||||||
|
|
||||||
private final ThreadItemListener<I> listener;
|
private volatile int revision = 0;
|
||||||
private final LinearLayoutManager layoutManager;
|
|
||||||
|
|
||||||
public ThreadItemAdapter(ThreadItemListener<I> listener,
|
public ThreadItemAdapter(ThreadItemListener<I> listener,
|
||||||
LinearLayoutManager layoutManager) {
|
LinearLayoutManager layoutManager) {
|
||||||
@@ -290,6 +292,29 @@ public abstract class ThreadItemAdapter<I extends ThreadItem>
|
|||||||
animatingItems.remove(item);
|
animatingItems.remove(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the adapter's revision counter. This method should be called on
|
||||||
|
* any thread before starting an asynchronous load that could overwrite
|
||||||
|
* other changes to the adapter, and called again on the UI thread before
|
||||||
|
* applying the changes from the asynchronous load. If the revision has
|
||||||
|
* changed between the two calls, the asynchronous load should be restarted
|
||||||
|
* without applying its changes. Otherwise {@link #incrementRevision()}
|
||||||
|
* should be called before applying the changes.
|
||||||
|
*/
|
||||||
|
public int getRevision() {
|
||||||
|
return revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the adapter's revision counter. This method should be called
|
||||||
|
* on the UI thread before applying any changes to the adapter that could
|
||||||
|
* be overwritten by an asynchronous load.
|
||||||
|
*/
|
||||||
|
@UiThread
|
||||||
|
public void incrementRevision() {
|
||||||
|
revision++;
|
||||||
|
}
|
||||||
|
|
||||||
protected interface ThreadItemListener<I> {
|
protected interface ThreadItemListener<I> {
|
||||||
|
|
||||||
void onItemVisible(I item);
|
void onItemVisible(I item);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import org.briarproject.api.sync.MessageId;
|
|||||||
import org.briarproject.util.StringUtils;
|
import org.briarproject.util.StringUtils;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static android.support.design.widget.Snackbar.make;
|
import static android.support.design.widget.Snackbar.make;
|
||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
@@ -42,6 +43,9 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI
|
|||||||
protected static final String KEY_INPUT_VISIBILITY = "inputVisibility";
|
protected static final String KEY_INPUT_VISIBILITY = "inputVisibility";
|
||||||
protected static final String KEY_REPLY_ID = "replyId";
|
protected static final String KEY_REPLY_ID = "replyId";
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(ThreadListActivity.class.getName());
|
||||||
|
|
||||||
protected A adapter;
|
protected A adapter;
|
||||||
protected BriarRecyclerView list;
|
protected BriarRecyclerView list;
|
||||||
protected TextInputView textInput;
|
protected TextInputView textInput;
|
||||||
@@ -106,18 +110,24 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI
|
|||||||
protected abstract void onNamedGroupLoaded(G groupItem);
|
protected abstract void onNamedGroupLoaded(G groupItem);
|
||||||
|
|
||||||
private void loadItems() {
|
private void loadItems() {
|
||||||
|
final int revision = adapter.getRevision();
|
||||||
getController().loadItems(
|
getController().loadItems(
|
||||||
new UiResultExceptionHandler<Collection<I>, DbException>(
|
new UiResultExceptionHandler<Collection<I>, DbException>(this) {
|
||||||
this) {
|
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(Collection<I> items) {
|
public void onResultUi(Collection<I> items) {
|
||||||
if (items.isEmpty()) {
|
if (revision == adapter.getRevision()) {
|
||||||
list.showData();
|
adapter.incrementRevision();
|
||||||
|
if (items.isEmpty()) {
|
||||||
|
list.showData();
|
||||||
|
} else {
|
||||||
|
adapter.setItems(items);
|
||||||
|
list.showData();
|
||||||
|
if (replyId != null)
|
||||||
|
adapter.setReplyItemById(replyId);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
adapter.setItems(items);
|
LOG.info("Concurrent update, reloading");
|
||||||
list.showData();
|
loadItems();
|
||||||
if (replyId != null)
|
|
||||||
adapter.setReplyItemById(replyId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,6 +281,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void addItem(final I item, boolean isLocal) {
|
protected void addItem(final I item, boolean isLocal) {
|
||||||
|
adapter.incrementRevision();
|
||||||
adapter.add(item);
|
adapter.add(item);
|
||||||
if (isLocal && adapter.isVisible(item)) {
|
if (isLocal && adapter.isVisible(item)) {
|
||||||
displaySnackbarShort(getItemPostedString());
|
displaySnackbarShort(getItemPostedString());
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.android.util;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.annotation.UiThread;
|
||||||
import android.support.v7.util.SortedList;
|
import android.support.v7.util.SortedList;
|
||||||
import android.support.v7.widget.RecyclerView.Adapter;
|
import android.support.v7.widget.RecyclerView.Adapter;
|
||||||
import android.support.v7.widget.RecyclerView.ViewHolder;
|
import android.support.v7.widget.RecyclerView.ViewHolder;
|
||||||
@@ -16,6 +17,8 @@ public abstract class BriarAdapter<T, V extends ViewHolder>
|
|||||||
protected final Context ctx;
|
protected final Context ctx;
|
||||||
protected final SortedList<T> items;
|
protected final SortedList<T> items;
|
||||||
|
|
||||||
|
private volatile int revision = 0;
|
||||||
|
|
||||||
public BriarAdapter(Context ctx, Class<T> c) {
|
public BriarAdapter(Context ctx, Class<T> c) {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.items = new SortedList<>(c, new SortedList.Callback<T>() {
|
this.items = new SortedList<>(c, new SortedList.Callback<T>() {
|
||||||
@@ -110,4 +113,26 @@ public abstract class BriarAdapter<T, V extends ViewHolder>
|
|||||||
return items.size() == 0;
|
return items.size() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the adapter's revision counter. This method should be called on
|
||||||
|
* any thread before starting an asynchronous load that could overwrite
|
||||||
|
* other changes to the adapter, and called again on the UI thread before
|
||||||
|
* applying the changes from the asynchronous load. If the revision has
|
||||||
|
* changed between the two calls, the asynchronous load should be restarted
|
||||||
|
* without applying its changes. Otherwise {@link #incrementRevision()}
|
||||||
|
* should be called before applying the changes.
|
||||||
|
*/
|
||||||
|
public int getRevision() {
|
||||||
|
return revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the adapter's revision counter. This method should be called
|
||||||
|
* on the UI thread before applying any changes to the adapter that could
|
||||||
|
* be overwritten by an asynchronous load.
|
||||||
|
*/
|
||||||
|
@UiThread
|
||||||
|
public void incrementRevision() {
|
||||||
|
revision++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user