diff --git a/briar-android/src/org/briarproject/android/forum/ForumItem.java b/briar-android/src/org/briarproject/android/forum/ForumItem.java
deleted file mode 100644
index 92ae9320bf7ec48eeeb6b77c6a00ce51bc17ab76..0000000000000000000000000000000000000000
--- a/briar-android/src/org/briarproject/android/forum/ForumItem.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package org.briarproject.android.forum;
-
-import org.briarproject.api.forum.ForumPostHeader;
-
-// This class is not thread-safe
-class ForumItem {
-
-	private final ForumPostHeader header;
-	private byte[] body;
-
-	ForumItem(ForumPostHeader header) {
-		this.header = header;
-		body = null;
-	}
-
-	ForumPostHeader getHeader() {
-		return header;
-	}
-
-	byte[] getBody() {
-		return body;
-	}
-
-	void setBody(byte[] body) {
-		this.body = body;
-	}
-}
diff --git a/briar-android/src/org/briarproject/android/forum/ForumItemComparator.java b/briar-android/src/org/briarproject/android/forum/ForumItemComparator.java
deleted file mode 100644
index d482b979b7d8e95caec1c15c61ce9c89d5f77693..0000000000000000000000000000000000000000
--- a/briar-android/src/org/briarproject/android/forum/ForumItemComparator.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package org.briarproject.android.forum;
-
-import java.util.Comparator;
-
-class ForumItemComparator implements Comparator<ForumItem> {
-
-	static final ForumItemComparator INSTANCE = new ForumItemComparator();
-
-	public int compare(ForumItem a, ForumItem b) {
-		// The oldest message comes first
-		long aTime = a.getHeader().getTimestamp();
-		long bTime = b.getHeader().getTimestamp();
-		if (aTime < bTime) return -1;
-		if (aTime > bTime) return 1;
-		return 0;
-	}
-}
diff --git a/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java b/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java
index 9c3ba15fe3d578a3c5269ae79999678bfdf95fda..83f2a793a3107be18a9525e0bbc76517f91dd0e4 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java
@@ -17,6 +17,7 @@ import org.briarproject.android.view.TextAvatarView;
 import org.briarproject.api.forum.Forum;
 import org.briarproject.api.sync.GroupId;
 
+import static android.support.v7.util.SortedList.INVALID_POSITION;
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
 import static org.briarproject.android.BriarActivity.GROUP_ID;
@@ -50,7 +51,7 @@ class ForumListAdapter
 		ui.name.setText(item.getForum().getName());
 
 		// Post Count
-		int postCount = item.getPostCount();
+		int postCount = (int) item.getPostCount();
 		if (postCount > 0) {
 			ui.avatar.setProblem(false);
 			ui.postCount.setText(ctx.getResources()
@@ -104,7 +105,7 @@ class ForumListAdapter
 
 	@Override
 	public boolean areContentsTheSame(ForumListItem a, ForumListItem b) {
-		return a.getForum().equals(b.getForum()) &&
+		return a.isEmpty() == b.isEmpty() &&
 				a.getTimestamp() == b.getTimestamp() &&
 				a.getUnreadCount() == b.getUnreadCount();
 	}
@@ -125,10 +126,14 @@ class ForumListAdapter
 		return null;
 	}
 
-	void updateItem(ForumListItem item) {
-		ForumListItem oldItem = findItem(item.getForum().getGroup().getId());
-		int position = items.indexOf(oldItem);
-		items.updateItemAt(position, item);
+	int findItemPosition(GroupId g) {
+		int count = getItemCount();
+		for (int i = 0; i < count; i++) {
+			ForumListItem item = getItemAt(i);
+			if (item != null && item.getForum().getGroup().getId().equals(g))
+				return i;
+		}
+		return INVALID_POSITION; // Not found
 	}
 
 	static class ForumViewHolder extends RecyclerView.ViewHolder {
diff --git a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
index 94f2e2e4e322b956f9b9a228e7e76059c3a1c401..70d82d05d974105f3ac5ba301f7fcf620727f19e 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
@@ -20,6 +20,7 @@ import org.briarproject.android.api.AndroidNotificationManager;
 import org.briarproject.android.fragment.BaseEventFragment;
 import org.briarproject.android.sharing.InvitationsForumActivity;
 import org.briarproject.android.view.BriarRecyclerView;
+import org.briarproject.api.clients.MessageTracker.GroupCount;
 import org.briarproject.api.db.DbException;
 import org.briarproject.api.db.NoSuchGroupException;
 import org.briarproject.api.event.ContactRemovedEvent;
@@ -47,11 +48,8 @@ import static java.util.logging.Level.WARNING;
 public class ForumListFragment extends BaseEventFragment implements
 		OnClickListener {
 
-	public final static String TAG = "ForumListFragment";
-
-	private static final Logger LOG =
-			Logger.getLogger(ForumListFragment.class.getName());
-
+	public final static String TAG = ForumListFragment.class.getName();
+	private final static Logger LOG = Logger.getLogger(TAG);
 
 	private BriarRecyclerView list;
 	private ForumListAdapter adapter;
@@ -118,7 +116,7 @@ public class ForumListFragment extends BaseEventFragment implements
 
 		notificationManager.blockAllForumPostNotifications();
 		notificationManager.clearAllForumPostNotifications();
-		loadForumHeaders();
+		loadForums();
 		loadAvailableForums();
 		list.startPeriodicUpdate();
 	}
@@ -153,7 +151,7 @@ public class ForumListFragment extends BaseEventFragment implements
 		}
 	}
 
-	private void loadForumHeaders() {
+	private void loadForums() {
 		listener.runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
@@ -163,14 +161,14 @@ public class ForumListFragment extends BaseEventFragment implements
 					Collection<ForumListItem> forums = new ArrayList<>();
 					for (Forum f : forumManager.getForums()) {
 						try {
-							Collection<ForumPostHeader> headers =
-									forumManager.getPostHeaders(f.getId());
-							forums.add(new ForumListItem(f, headers));
+							GroupCount count =
+									forumManager.getGroupCount(f.getId());
+							forums.add(new ForumListItem(f, count));
 						} catch (NoSuchGroupException e) {
 							// Continue
 						}
 					}
-					displayForumHeaders(forums);
+					displayForums(forums);
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Full load took " + duration + " ms");
@@ -182,7 +180,7 @@ public class ForumListFragment extends BaseEventFragment implements
 		});
 	}
 
-	private void displayForumHeaders(final Collection<ForumListItem> forums) {
+	private void displayForums(final Collection<ForumListItem> forums) {
 		listener.runOnUiThread(new Runnable() {
 			@Override
 			public void run() {
@@ -238,7 +236,7 @@ public class ForumListFragment extends BaseEventFragment implements
 			GroupAddedEvent g = (GroupAddedEvent) e;
 			if (g.getGroup().getClientId().equals(forumManager.getClientId())) {
 				LOG.info("Forum added, reloading forums");
-				loadForumHeaders();
+				loadForums();
 			}
 		} else if (e instanceof GroupRemovedEvent) {
 			GroupRemovedEvent g = (GroupRemovedEvent) e;
@@ -248,39 +246,23 @@ public class ForumListFragment extends BaseEventFragment implements
 			}
 		} else if (e instanceof ForumPostReceivedEvent) {
 			ForumPostReceivedEvent m = (ForumPostReceivedEvent) e;
-			LOG.info("Forum post added, reloading");
-			loadForumHeaders(m.getGroupId());
+			LOG.info("Forum post added, updating...");
+			updateItem(m.getGroupId(), m.getForumPostHeader());
 		} else if (e instanceof ForumInvitationReceivedEvent) {
 			loadAvailableForums();
 		}
 	}
 
-	private void loadForumHeaders(final GroupId g) {
-		listener.runOnDbThread(new Runnable() {
-			@Override
-			public void run() {
-				try {
-					long now = System.currentTimeMillis();
-					Forum f = forumManager.getForum(g);
-					Collection<ForumPostHeader> headers =
-							forumManager.getPostHeaders(g);
-					long duration = System.currentTimeMillis() - now;
-					if (LOG.isLoggable(INFO))
-						LOG.info("Partial load took " + duration + " ms");
-					updateForum(new ForumListItem(f, headers));
-				} catch (DbException e) {
-					if (LOG.isLoggable(WARNING))
-						LOG.log(WARNING, e.toString(), e);
-				}
-			}
-		});
-	}
-
-	private void updateForum(final ForumListItem item) {
+	private void updateItem(final GroupId g, final ForumPostHeader m) {
 		listener.runOnUiThread(new Runnable() {
 			@Override
 			public void run() {
-				adapter.updateItem(item);
+				int position = adapter.findItemPosition(g);
+				ForumListItem item = adapter.getItemAt(position);
+				if (item != null) {
+					item.addHeader(m);
+					adapter.updateItemAt(position, item);
+				}
 			}
 		});
 	}
@@ -289,7 +271,8 @@ public class ForumListFragment extends BaseEventFragment implements
 		listener.runOnUiThread(new Runnable() {
 			@Override
 			public void run() {
-				ForumListItem item = adapter.findItem(g);
+				int position = adapter.findItemPosition(g);
+				ForumListItem item = adapter.getItemAt(position);
 				if (item != null) adapter.remove(item);
 			}
 		});
diff --git a/briar-android/src/org/briarproject/android/forum/ForumListItem.java b/briar-android/src/org/briarproject/android/forum/ForumListItem.java
index 27ba86815e770d2a28115c096e1f905bbc39efbb..3b8d4e98998c64fef1278de3641653a690268b56 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumListItem.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumListItem.java
@@ -1,41 +1,26 @@
 package org.briarproject.android.forum;
 
+import org.briarproject.api.clients.MessageTracker.GroupCount;
 import org.briarproject.api.forum.Forum;
 import org.briarproject.api.forum.ForumPostHeader;
 
-import java.util.Collection;
-
 // This class is NOT thread-safe
 class ForumListItem {
 
 	private final Forum forum;
-	private final boolean empty;
-	private final int postCount;
-	private final long timestamp;
-	private final int unread;
+	private long postCount, unread, timestamp;
 
-	ForumListItem(Forum forum, Collection<ForumPostHeader> headers) {
+	ForumListItem(Forum forum, GroupCount count) {
 		this.forum = forum;
-		empty = headers.isEmpty();
-		if (empty) {
-			postCount = 0;
-			timestamp = 0;
-			unread = 0;
-		} else {
-			ForumPostHeader newest = null;
-			long timestamp = -1;
-			int unread = 0;
-			for (ForumPostHeader h : headers) {
-				if (h.getTimestamp() > timestamp) {
-					timestamp = h.getTimestamp();
-					newest = h;
-				}
-				if (!h.isRead()) unread++;
-			}
-			this.postCount = headers.size();
-			this.timestamp = newest.getTimestamp();
-			this.unread = unread;
-		}
+		this.postCount = count.getMsgCount();
+		this.unread = count.getUnreadCount();
+		this.timestamp = count.getLatestMsgTime();
+	}
+
+	void addHeader(ForumPostHeader h) {
+		postCount++;
+		if (!h.isRead()) unread++;
+		if (h.getTimestamp() > timestamp) timestamp = h.getTimestamp();
 	}
 
 	Forum getForum() {
@@ -43,10 +28,10 @@ class ForumListItem {
 	}
 
 	boolean isEmpty() {
-		return empty;
+		return postCount == 0;
 	}
 
-	int getPostCount() {
+	long getPostCount() {
 		return postCount;
 	}
 
@@ -54,7 +39,7 @@ class ForumListItem {
 		return timestamp;
 	}
 
-	int getUnreadCount() {
+	long getUnreadCount() {
 		return unread;
 	}
 }
diff --git a/briar-android/src/org/briarproject/android/view/TextAvatarView.java b/briar-android/src/org/briarproject/android/view/TextAvatarView.java
index 70ab3f3981bc18138cce89dfee9a5d6c791c0199..0b4e3703eea7b90e49e3a0e9d78ddbeeff949654 100644
--- a/briar-android/src/org/briarproject/android/view/TextAvatarView.java
+++ b/briar-android/src/org/briarproject/android/view/TextAvatarView.java
@@ -24,7 +24,7 @@ public class TextAvatarView extends FrameLayout {
 	final private AppCompatTextView character;
 	final private CircleImageView background;
 	final private TextView badge;
-	private int unreadCount;
+	private long unreadCount;
 
 	public TextAvatarView(Context context, @Nullable AttributeSet attrs) {
 		super(context, attrs);
@@ -48,13 +48,19 @@ public class TextAvatarView extends FrameLayout {
 	}
 
 	public void setUnreadCount(int count) {
+		setUnreadCount((long) count);
+	}
+
+	public void setUnreadCount(long count) {
+		this.unreadCount = count;
 		if (count > 0) {
-			this.unreadCount = count;
 			badge.setBackgroundResource(R.drawable.bubble);
 			badge.setText(String.valueOf(count));
-			badge.setTextColor(ContextCompat.getColor(getContext(), R.color.briar_text_primary_inverse));
+			badge.setTextColor(ContextCompat.getColor(getContext(),
+					R.color.briar_text_primary_inverse));
 			badge.setVisibility(VISIBLE);
 		} else {
+			badge.setText("");
 			badge.setVisibility(INVISIBLE);
 		}
 	}
@@ -63,11 +69,13 @@ public class TextAvatarView extends FrameLayout {
 		if (problem) {
 			badge.setBackgroundResource(R.drawable.bubble_problem);
 			badge.setText("!");
-			badge.setTextColor(ContextCompat.getColor(getContext(), R.color.briar_primary));
+			badge.setTextColor(ContextCompat
+					.getColor(getContext(), R.color.briar_primary));
 			badge.setVisibility(VISIBLE);
 		} else if (unreadCount > 0) {
 			setUnreadCount(unreadCount);
 		} else {
+			badge.setText("");
 			badge.setVisibility(INVISIBLE);
 		}
 	}