diff --git a/briar-android/res/layout/briar_recycler_view.xml b/briar-android/res/layout/briar_recycler_view.xml
index 255cbe6634c560b3ddbd93d0ad82ca4400844e4c..2f3d6fc5a73c7836f54b1d498045be98f937c563 100644
--- a/briar-android/res/layout/briar_recycler_view.xml
+++ b/briar-android/res/layout/briar_recycler_view.xml
@@ -24,6 +24,7 @@
 		android:layout_width="wrap_content"
 		android:layout_height="wrap_content"
 		android:layout_centerInParent="true"
+		android:padding="@dimen/margin_activity_horizontal"
 		android:textSize="@dimen/text_size_large"
 		android:text="@string/no_data"/>
 
diff --git a/briar-android/res/layout/fragment_forum_list.xml b/briar-android/res/layout/fragment_forum_list.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c823c26c1b5b3dc6a764ab3e4aa724a4fe14d5a0
--- /dev/null
+++ b/briar-android/res/layout/fragment_forum_list.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<org.briarproject.android.util.BriarRecyclerView
+	android:id="@+id/forumList"
+	xmlns:android="http://schemas.android.com/apk/res/android"
+	android:layout_width="match_parent"
+	android:layout_height="match_parent"/>
diff --git a/briar-android/res/layout/list_item_forum.xml b/briar-android/res/layout/list_item_forum.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8462c1cd68748749b5649af3a404166f256200f4
--- /dev/null
+++ b/briar-android/res/layout/list_item_forum.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+	xmlns:android="http://schemas.android.com/apk/res/android"
+	xmlns:tools="http://schemas.android.com/tools"
+	android:layout_width="match_parent"
+	android:layout_height="wrap_content"
+	android:layout_marginLeft="@dimen/listitem_horizontal_margin"
+	android:layout_marginStart="@dimen/listitem_horizontal_margin"
+	android:paddingTop="@dimen/listitem_horizontal_margin"
+	android:background="?attr/selectableItemBackground">
+
+	<TextView
+		android:id="@+id/forumNameView"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:maxLines="2"
+		android:textColor="@color/briar_text_primary"
+		android:textSize="@dimen/text_size_medium"
+		tools:text="This is a name of a forum"/>
+
+	<TextView
+		android:id="@+id/unreadView"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_alignParentLeft="true"
+		android:layout_alignParentStart="true"
+		android:layout_below="@+id/forumNameView"
+		android:layout_toLeftOf="@+id/dateView"
+		android:paddingTop="@dimen/margin_medium"
+		android:paddingBottom="@dimen/listitem_horizontal_margin"
+		android:textColor="@color/briar_text_secondary"
+		android:textSize="@dimen/text_size_small"
+		android:text="@string/no_unread_posts"/>
+
+	<TextView
+		android:id="@+id/dateView"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_alignParentRight="true"
+		android:layout_alignParentEnd="true"
+		android:layout_below="@+id/forumNameView"
+		android:paddingTop="@dimen/margin_medium"
+		android:paddingBottom="@dimen/listitem_horizontal_margin"
+		android:layout_marginRight="@dimen/listitem_horizontal_margin"
+		android:layout_marginEnd="@dimen/listitem_horizontal_margin"
+		android:textColor="@color/briar_text_secondary"
+		android:textSize="@dimen/text_size_small"
+		tools:text="Dec 24"/>
+
+	<View style="@style/Divider.ForumList"
+	      android:layout_below="@+id/unreadView"
+	      android:layout_alignParentLeft="true"
+	      android:layout_alignParentStart="true"/>
+
+</RelativeLayout>
+
diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index c2ed50e249569f32040e84245652d81f623e5a13..e5d21dec3eef771234840b9167a10436bda80f47 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -72,7 +72,7 @@
 	<string name="private_message_hint">Type message</string>
 	<string name="message_sent_toast">Message sent</string>
 	<string name="forums_title">Forums</string>
-	<string name="no_forums">No forums</string>
+	<string name="no_forums">You don\'t have any forums.\n\nWhy don\'t you create a new one yourself or ask your contacts to share one with you?</string>
 	<plurals name="forums_shared">
 		<item quantity="one">%d forum shared by contacts</item>
 		<item quantity="other">%d forums shared by contacts</item>
@@ -81,6 +81,11 @@
 	<string name="forum_leave">Leave Forum</string>
 	<string name="forum_left_toast">Left Forum</string>
 	<string name="no_forum_posts">No posts</string>
+	<string name="no_unread_posts">no unread posts</string>
+	<plurals name="unread_posts">
+		<item quantity="one">%d unread post</item>
+		<item quantity="other">%d unread posts</item>
+	</plurals>
 	<string name="create_forum_title">New Forum</string>
 	<string name="choose_forum_name">Choose a name for your forum:</string>
 	<string name="create_forum_button">Create Forum</string>
diff --git a/briar-android/res/values/styles.xml b/briar-android/res/values/styles.xml
index 22ad6a119f21c4e8ccc37757bd767e6035d68ed9..7b328e17f38a9632531c09e484832817d028ec8c 100644
--- a/briar-android/res/values/styles.xml
+++ b/briar-android/res/values/styles.xml
@@ -107,6 +107,11 @@
 		<item name="android:layout_marginLeft">@dimen/margin_large</item>
 	</style>
 
+	<style name="Divider.ForumList" parent="Divider">
+		<item name="android:layout_width">match_parent</item>
+		<item name="android:layout_height">1dp</item>
+	</style>
+
 	<style name="NavMenuButton" parent="Widget.AppCompat.Button.Borderless.Colored">
 		<item name="android:textSize">@dimen/text_size_medium</item>
 		<item name="android:textColor">@android:color/tertiary_text_light</item>
diff --git a/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java b/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java
index 0fb713a74d443b45c2a85f0461e8449ef65022c2..7eb5dc3eab4d9d8af69e30a7c1f09fd56583dcf8 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java
@@ -1,70 +1,193 @@
 package org.briarproject.android.forum;
 
 import android.content.Context;
-import android.content.res.Resources;
+import android.content.Intent;
+import android.support.annotation.Nullable;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.util.SortedList;
+import android.support.v7.widget.RecyclerView;
 import android.text.format.DateUtils;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import org.briarproject.R;
-import org.briarproject.android.util.LayoutUtils;
+import org.briarproject.api.forum.Forum;
+import org.briarproject.api.sync.GroupId;
 
-import java.util.ArrayList;
+import java.util.Collection;
 
-import static android.text.TextUtils.TruncateAt.END;
-import static android.widget.LinearLayout.HORIZONTAL;
-import static org.briarproject.android.util.CommonLayoutParams.WRAP_WRAP_1;
+import static org.briarproject.android.BriarActivity.GROUP_ID;
+import static org.briarproject.android.forum.ForumActivity.FORUM_NAME;
 
-public class ForumListAdapter extends ArrayAdapter<ForumListItem> {
+public class ForumListAdapter extends
+		RecyclerView.Adapter<ForumListAdapter.ForumViewHolder> {
 
-	private final int pad;
+	private SortedList<ForumListItem> forums = new SortedList<>(
+			ForumListItem.class, new SortedList.Callback<ForumListItem>() {
+		@Override
+		public int compare(ForumListItem a, ForumListItem b) {
+			if (a == b) return 0;
+			// The forum with the newest message comes first
+			long aTime = a.getTimestamp(), bTime = b.getTimestamp();
+			if (aTime > bTime) return -1;
+			if (aTime < bTime) return 1;
+			// Break ties by forum name
+			String aName = a.getForum().getName();
+			String bName = b.getForum().getName();
+			return String.CASE_INSENSITIVE_ORDER.compare(aName, bName);
+		}
+
+		@Override
+		public void onInserted(int position, int count) {
+			notifyItemRangeInserted(position, count);
+		}
+
+		@Override
+		public void onRemoved(int position, int count) {
+			notifyItemRangeRemoved(position, count);
+		}
+
+		@Override
+		public void onMoved(int fromPosition, int toPosition) {
+			notifyItemMoved(fromPosition, toPosition);
+		}
+
+		@Override
+		public void onChanged(int position, int count) {
+			notifyItemRangeChanged(position, count);
+		}
+
+		@Override
+		public boolean areContentsTheSame(ForumListItem a, ForumListItem b) {
+			return a.getForum().equals(b.getForum()) &&
+					a.getTimestamp() == b.getTimestamp() &&
+					a.getUnreadCount() == b.getUnreadCount();
+		}
+
+		@Override
+		public boolean areItemsTheSame(ForumListItem a, ForumListItem b) {
+			return a.getForum().equals(b.getForum());
+		}
+	});
+	private final Context ctx;
 
 	public ForumListAdapter(Context ctx) {
-		super(ctx, android.R.layout.simple_expandable_list_item_1,
-				new ArrayList<ForumListItem>());
-		pad = LayoutUtils.getPadding(ctx);
+		this.ctx = ctx;
+	}
+
+	@Override
+	public ForumViewHolder onCreateViewHolder(ViewGroup parent,
+			int viewType) {
+
+		View v = LayoutInflater.from(ctx)
+				.inflate(R.layout.list_item_forum, parent, false);
+		return new ForumViewHolder(v);
 	}
 
 	@Override
-	public View getView(int position, View convertView, ViewGroup parent) {
-		ForumListItem item = getItem(position);
-		Context ctx = getContext();
-		Resources res = ctx.getResources();
+	public void onBindViewHolder(ForumViewHolder ui, int position) {
+		final ForumListItem item = getItem(position);
+
+		// TODO add avatar. See #337
 
-		LinearLayout layout = new LinearLayout(ctx);
-		layout.setOrientation(HORIZONTAL);
+		// Forum Name
+		ui.name.setText(item.getForum().getName());
+
+		// Unread Count
 		int unread = item.getUnreadCount();
-		if (unread > 0)
-			layout.setBackgroundColor(res.getColor(R.color.unread_background));
-
-		TextView name = new TextView(ctx);
-		name.setLayoutParams(WRAP_WRAP_1);
-		name.setTextSize(18);
-		name.setSingleLine();
-		name.setEllipsize(END);
-		name.setPadding(pad, pad, pad, pad);
-		String forumName = item.getForum().getName();
-		if (unread > 0) name.setText(forumName + " (" + unread + ")");
-		else name.setText(forumName);
-		layout.addView(name);
+		if (unread > 0) {
+			ui.unread.setText(ctx.getResources()
+					.getQuantityString(R.plurals.unread_posts, unread, unread));
+			ui.unread.setTextColor(
+					ContextCompat.getColor(ctx, R.color.briar_button_positive));
+		} else {
+			ui.unread.setText(ctx.getString(R.string.no_unread_posts));
+			ui.unread.setTextColor(
+					ContextCompat.getColor(ctx, R.color.briar_text_secondary));
+		}
 
+		// Date or "No Posts"
 		if (item.isEmpty()) {
-			TextView noPosts = new TextView(ctx);
-			noPosts.setPadding(pad, 0, pad, pad);
-			noPosts.setTextColor(res.getColor(R.color.no_posts));
-			noPosts.setText(R.string.no_forum_posts);
-			layout.addView(noPosts);
+			ui.date.setVisibility(View.GONE);
 		} else {
-			TextView date = new TextView(ctx);
-			date.setPadding(pad, 0, pad, pad);
 			long timestamp = item.getTimestamp();
-			date.setText(DateUtils.getRelativeTimeSpanString(ctx, timestamp));
-			layout.addView(date);
+			ui.date.setText(
+					DateUtils.getRelativeTimeSpanString(ctx, timestamp));
+			ui.date.setVisibility(View.VISIBLE);
+		}
+
+		// Open Forum on Click
+		ui.layout.setOnClickListener(new View.OnClickListener() {
+			@Override
+			public void onClick(View v) {
+				Intent i = new Intent(ctx, ForumActivity.class);
+				Forum f = item.getForum();
+				i.putExtra(GROUP_ID, f.getId().getBytes());
+				i.putExtra(FORUM_NAME, f.getName());
+				ctx.startActivity(i);
+			}
+		});
+	}
+
+	@Override
+	public int getItemCount() {
+		return forums.size();
+	}
+
+	public ForumListItem getItem(int position) {
+		return forums.get(position);
+	}
+
+	@Nullable
+	public ForumListItem getItem(GroupId g) {
+		for (int i = 0; i < forums.size(); i++) {
+			ForumListItem item = forums.get(i);
+			if (item.getForum().getGroup().getId().equals(g)) {
+				return item;
+			}
 		}
+		return null;
+	}
+
+	public void addAll(Collection<ForumListItem> items) {
+		forums.addAll(items);
+	}
+
+	public void updateItem(ForumListItem item) {
+		ForumListItem oldItem = getItem(item.getForum().getGroup().getId());
+		int position = forums.indexOf(oldItem);
+		forums.updateItemAt(position, item);
+	}
 
-		return layout;
+	public void remove(ForumListItem item) {
+		forums.remove(item);
 	}
+
+	public void clear() {
+		forums.clear();
+	}
+
+	public boolean isEmpty() {
+		return forums.size() == 0;
+	}
+
+	protected static class ForumViewHolder extends RecyclerView.ViewHolder {
+
+		public final ViewGroup layout;
+		public final TextView name;
+		public final TextView unread;
+		public final TextView date;
+
+		public ForumViewHolder(View v) {
+			super(v);
+
+			layout = (ViewGroup) v;
+			name = (TextView) v.findViewById(R.id.forumNameView);
+			unread = (TextView) v.findViewById(R.id.unreadView);
+			date = (TextView) v.findViewById(R.id.dateView);
+		}
+	}
+
 }
diff --git a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
index bd5a62026df793cecd10185dadd021ddec410104..4aa853bd7e42dc5d04db6037ac689543c41566fd 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
@@ -5,25 +5,23 @@ import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.design.widget.Snackbar;
 import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.LinearLayoutManager;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.LinearLayout;
-import android.widget.ListView;
-import android.widget.TextView;
 
 import org.briarproject.R;
 import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.fragment.BaseEventFragment;
-import org.briarproject.android.util.ListLoadingProgressBar;
+import org.briarproject.android.util.BriarRecyclerView;
 import org.briarproject.api.db.DbException;
 import org.briarproject.api.db.NoSuchGroupException;
 import org.briarproject.api.event.ContactRemovedEvent;
 import org.briarproject.api.event.Event;
+import org.briarproject.api.event.ForumInvitationReceivedEvent;
 import org.briarproject.api.event.GroupAddedEvent;
 import org.briarproject.api.event.GroupRemovedEvent;
 import org.briarproject.api.event.MessageValidatedEvent;
@@ -34,26 +32,18 @@ import org.briarproject.api.forum.ForumSharingManager;
 import org.briarproject.api.sync.ClientId;
 import org.briarproject.api.sync.GroupId;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
 import static android.support.design.widget.Snackbar.LENGTH_INDEFINITE;
-import static android.view.Gravity.CENTER;
-import static android.view.Gravity.CENTER_HORIZONTAL;
-import static android.view.View.GONE;
-import static android.view.View.VISIBLE;
-import static android.widget.LinearLayout.VERTICAL;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
-import static org.briarproject.android.BriarActivity.GROUP_ID;
-import static org.briarproject.android.forum.ForumActivity.FORUM_NAME;
-import static org.briarproject.android.util.CommonLayoutParams.MATCH_MATCH;
-import static org.briarproject.android.util.CommonLayoutParams.MATCH_WRAP_1;
 
 public class ForumListFragment extends BaseEventFragment implements
-		AdapterView.OnItemClickListener, View.OnClickListener {
+		View.OnClickListener {
 
 	public final static String TAG = "ForumListFragment";
 
@@ -69,10 +59,8 @@ public class ForumListFragment extends BaseEventFragment implements
 		return fragment;
 	}
 
-	private TextView empty = null;
-	private ForumListAdapter adapter = null;
-	private ListView list = null;
-	private ListLoadingProgressBar loading = null;
+	private BriarRecyclerView list;
+	private ForumListAdapter adapter;
 	private Snackbar snackbar;
 
 	// Fields that are accessed from background threads must be volatile
@@ -86,32 +74,24 @@ public class ForumListFragment extends BaseEventFragment implements
 
 		setHasOptionsMenu(true);
 
-		LinearLayout layout = new LinearLayout(getContext());
-		layout.setLayoutParams(MATCH_MATCH);
-		layout.setOrientation(VERTICAL);
-		layout.setGravity(CENTER_HORIZONTAL);
-
-		empty = new TextView(getContext());
-		empty.setLayoutParams(MATCH_WRAP_1);
-		empty.setGravity(CENTER);
-		empty.setTextSize(18);
-		empty.setText(R.string.no_forums);
-		empty.setVisibility(GONE);
-		layout.addView(empty);
-
-		adapter = new ForumListAdapter(getContext());
-		list = new ListView(getContext());
-		list.setLayoutParams(MATCH_WRAP_1);
+		View contentView =
+				inflater.inflate(R.layout.fragment_forum_list, container,
+						false);
+
+		adapter = new ForumListAdapter(getActivity());
+
+		list = (BriarRecyclerView) contentView.findViewById(R.id.forumList);
+		list.setLayoutManager(new LinearLayoutManager(getActivity()));
 		list.setAdapter(adapter);
-		list.setOnItemClickListener(this);
-		list.setVisibility(GONE);
-		layout.addView(list);
+		list.setEmptyText(getString(R.string.no_forums));
 
-		// Show a progress bar while the list is loading
-		loading = new ListLoadingProgressBar(getContext());
-		layout.addView(loading);
+		snackbar = Snackbar.make(contentView, "", LENGTH_INDEFINITE);
+		snackbar.getView().setBackgroundResource(R.color.briar_primary);
+		snackbar.setAction(R.string.show_forums, this);
+		snackbar.setActionTextColor(ContextCompat
+				.getColor(getContext(), R.color.briar_button_positive));
 
-		return layout;
+		return contentView;
 	}
 
 	@Override
@@ -128,13 +108,15 @@ public class ForumListFragment extends BaseEventFragment implements
 	public void onResume() {
 		super.onResume();
 
-		snackbar = Snackbar.make(getView(), "", LENGTH_INDEFINITE);
-		snackbar.getView().setBackgroundResource(R.color.briar_primary);
-		snackbar.setAction(R.string.show_forums, this);
-		snackbar.setActionTextColor(ContextCompat
-				.getColor(getContext(), R.color.briar_button_positive));
+		loadForumHeaders();
+		loadAvailableForums();
+	}
+
+	@Override
+	public void onPause() {
+		super.onPause();
 
-		loadHeaders();
+		adapter.clear();
 	}
 
 	@Override
@@ -157,30 +139,26 @@ public class ForumListFragment extends BaseEventFragment implements
 		}
 	}
 
-	private void loadHeaders() {
-		clearHeaders();
+	private void loadForumHeaders() {
 		listener.runOnDbThread(new Runnable() {
 			public void run() {
 				try {
+					// load forums
 					long now = System.currentTimeMillis();
-					boolean displayedHeaders = false;
+					Collection<ForumListItem> forums = new ArrayList<>();
 					for (Forum f : forumManager.getForums()) {
 						try {
 							Collection<ForumPostHeader> headers =
 									forumManager.getPostHeaders(f.getId());
-							displayHeaders(f, headers);
-							displayedHeaders = true;
+							forums.add(new ForumListItem(f, headers));
 						} catch (NoSuchGroupException e) {
 							// Continue
 						}
 					}
-					int available =
-							forumSharingManager.getAvailableForums().size();
+					displayForumHeaders(forums);
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Full load took " + duration + " ms");
-					if (!displayedHeaders) displayEmpty();
-					displayAvailable(available);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
@@ -189,45 +167,35 @@ public class ForumListFragment extends BaseEventFragment implements
 		});
 	}
 
-	private void clearHeaders() {
+	private void displayForumHeaders(final Collection<ForumListItem> forums) {
 		listener.runOnUiThread(new Runnable() {
 			public void run() {
-				empty.setVisibility(GONE);
-				list.setVisibility(GONE);
-				snackbar.dismiss();
-				loading.setVisibility(VISIBLE);
-				adapter.clear();
+				if (forums.size() > 0) adapter.addAll(forums);
+				else list.showData();
 			}
 		});
 	}
 
-	private void displayHeaders(final Forum f,
-			final Collection<ForumPostHeader> headers) {
-		listener.runOnUiThread(new Runnable() {
-			public void run() {
-				list.setVisibility(VISIBLE);
-				loading.setVisibility(GONE);
-				// Remove the old item, if any
-				ForumListItem item = findForum(f.getId());
-				if (item != null) adapter.remove(item);
-				// Add a new item
-				adapter.add(new ForumListItem(f, headers));
-				adapter.sort(ForumListItemComparator.INSTANCE);
-				selectFirstUnread();
-			}
-		});
-	}
-
-	private void displayEmpty() {
-		listener.runOnUiThread(new Runnable() {
+	private void loadAvailableForums() {
+		listener.runOnDbThread(new Runnable() {
 			public void run() {
-				empty.setVisibility(VISIBLE);
-				loading.setVisibility(GONE);
+				try {
+					long now = System.currentTimeMillis();
+					int available =
+							forumSharingManager.getAvailableForums().size();
+					long duration = System.currentTimeMillis() - now;
+					if (LOG.isLoggable(INFO))
+						LOG.info("Loading available took " + duration + " ms");
+					displayAvailableForums(available);
+				} catch (DbException e) {
+					if (LOG.isLoggable(WARNING))
+						LOG.log(WARNING, e.toString(), e);
+				}
 			}
 		});
 	}
 
-	private void displayAvailable(final int availableCount) {
+	private void displayAvailableForums(final int availableCount) {
 		listener.runOnUiThread(new Runnable() {
 			public void run() {
 				if (availableCount == 0) {
@@ -242,42 +210,21 @@ public class ForumListFragment extends BaseEventFragment implements
 		});
 	}
 
-	private ForumListItem findForum(GroupId g) {
-		int count = adapter.getCount();
-		for (int i = 0; i < count; i++) {
-			ForumListItem item = adapter.getItem(i);
-			if (item.getForum().getId().equals(g)) return item;
-		}
-		return null; // Not found
-	}
-
-	private void selectFirstUnread() {
-		int firstUnread = -1, count = adapter.getCount();
-		for (int i = 0; i < count; i++) {
-			if (adapter.getItem(i).getUnreadCount() > 0) {
-				firstUnread = i;
-				break;
-			}
-		}
-		if (firstUnread == -1) list.setSelection(count - 1);
-		else list.setSelection(firstUnread);
-	}
-
 	public void eventOccurred(Event e) {
 		if (e instanceof ContactRemovedEvent) {
-			LOG.info("Contact removed, reloading");
-			loadAvailable();
+			LOG.info("Contact removed, reloading available forums");
+			loadAvailableForums();
 		} else if (e instanceof GroupAddedEvent) {
 			GroupAddedEvent g = (GroupAddedEvent) e;
 			if (g.getGroup().getClientId().equals(forumManager.getClientId())) {
-				LOG.info("Forum added, reloading");
-				loadHeaders();
+				LOG.info("Forum added, reloading forums");
+				loadForumHeaders();
 			}
 		} else if (e instanceof GroupRemovedEvent) {
 			GroupRemovedEvent g = (GroupRemovedEvent) e;
 			if (g.getGroup().getClientId().equals(forumManager.getClientId())) {
-				LOG.info("Forum removed, reloading");
-				loadHeaders();
+				LOG.info("Forum removed, removing from list");
+				removeForum(g.getGroup().getId());
 			}
 		} else if (e instanceof MessageValidatedEvent) {
 			MessageValidatedEvent m = (MessageValidatedEvent) e;
@@ -285,17 +232,15 @@ public class ForumListFragment extends BaseEventFragment implements
 				ClientId c = m.getClientId();
 				if (c.equals(forumManager.getClientId())) {
 					LOG.info("Forum post added, reloading");
-					loadHeaders(m.getMessage().getGroupId());
-				} else if (!m.isLocal()
-						&& c.equals(forumSharingManager.getClientId())) {
-					LOG.info("Available forums updated, reloading");
-					loadAvailable();
+					loadForumHeaders(m.getMessage().getGroupId());
 				}
 			}
+		} else if (e instanceof ForumInvitationReceivedEvent) {
+			loadAvailableForums();
 		}
 	}
 
-	private void loadHeaders(final GroupId g) {
+	private void loadForumHeaders(final GroupId g) {
 		listener.runOnDbThread(new Runnable() {
 			public void run() {
 				try {
@@ -306,9 +251,7 @@ public class ForumListFragment extends BaseEventFragment implements
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Partial load took " + duration + " ms");
-					displayHeaders(f, headers);
-				} catch (NoSuchGroupException e) {
-					removeForum(g);
+					updateForum(new ForumListItem(f, headers));
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
@@ -317,38 +260,21 @@ public class ForumListFragment extends BaseEventFragment implements
 		});
 	}
 
-	private void removeForum(final GroupId g) {
+	private void updateForum(final ForumListItem item) {
 		listener.runOnUiThread(new Runnable() {
+			@Override
 			public void run() {
-				ForumListItem item = findForum(g);
-				if (item != null) {
-					adapter.remove(item);
-					if (adapter.isEmpty()) {
-						empty.setVisibility(VISIBLE);
-						list.setVisibility(GONE);
-					} else {
-						selectFirstUnread();
-					}
-				}
+				adapter.updateItem(item);
 			}
 		});
 	}
 
-	private void loadAvailable() {
-		listener.runOnDbThread(new Runnable() {
+	private void removeForum(final GroupId g) {
+		listener.runOnUiThread(new Runnable() {
+			@Override
 			public void run() {
-				try {
-					long now = System.currentTimeMillis();
-					int available =
-							forumSharingManager.getAvailableForums().size();
-					long duration = System.currentTimeMillis() - now;
-					if (LOG.isLoggable(INFO))
-						LOG.info("Loading available took " + duration + " ms");
-					displayAvailable(available);
-				} catch (DbException e) {
-					if (LOG.isLoggable(WARNING))
-						LOG.log(WARNING, e.toString(), e);
-				}
+				ForumListItem item = adapter.getItem(g);
+				if (item != null) adapter.remove(item);
 			}
 		});
 	}
@@ -358,13 +284,4 @@ public class ForumListFragment extends BaseEventFragment implements
 		startActivity(new Intent(getContext(), AvailableForumsActivity.class));
 	}
 
-	public void onItemClick(AdapterView<?> parent, View view, int position,
-			long id) {
-		Intent i = new Intent(getContext(), ForumActivity.class);
-		Forum f = adapter.getItem(position).getForum();
-		i.putExtra(GROUP_ID, f.getId().getBytes());
-		i.putExtra(FORUM_NAME, f.getName());
-		startActivity(i);
-	}
-
 }
diff --git a/briar-android/src/org/briarproject/android/forum/ForumListItemComparator.java b/briar-android/src/org/briarproject/android/forum/ForumListItemComparator.java
deleted file mode 100644
index bc50231c30d85a47d1baf68794a4832a3829dd11..0000000000000000000000000000000000000000
--- a/briar-android/src/org/briarproject/android/forum/ForumListItemComparator.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.briarproject.android.forum;
-
-import java.util.Comparator;
-
-public class ForumListItemComparator implements Comparator<ForumListItem> {
-
-	public static final ForumListItemComparator INSTANCE =
-			new ForumListItemComparator();
-
-	public int compare(ForumListItem a, ForumListItem b) {
-		if (a == b) return 0;
-		// The forum with the newest message comes first
-		long aTime = a.getTimestamp(), bTime = b.getTimestamp();
-		if (aTime > bTime) return -1;
-		if (aTime < bTime) return 1;
-		// Break ties by forum name
-		String aName = a.getForum().getName();
-		String bName = b.getForum().getName();
-		return String.CASE_INSENSITIVE_ORDER.compare(aName, bName);
-	}
-}