diff --git a/briar-android/src/org/briarproject/android/AndroidComponent.java b/briar-android/src/org/briarproject/android/AndroidComponent.java
index 3e59233be3dc1542bfa2b4867cb90197cc5c6e39..accd45a4cdedfc1b33c49780842fab34b3880741 100644
--- a/briar-android/src/org/briarproject/android/AndroidComponent.java
+++ b/briar-android/src/org/briarproject/android/AndroidComponent.java
@@ -5,8 +5,6 @@ import org.briarproject.CoreModule;
 import org.briarproject.android.api.AndroidExecutor;
 import org.briarproject.android.api.AndroidNotificationManager;
 import org.briarproject.android.api.ReferenceManager;
-import org.briarproject.android.blogs.BlogPersistentData;
-import org.briarproject.android.forum.ForumPersistentData;
 import org.briarproject.android.report.BriarReportSender;
 import org.briarproject.api.blogs.BlogManager;
 import org.briarproject.api.blogs.BlogPostFactory;
@@ -34,7 +32,6 @@ import org.briarproject.api.messaging.MessagingManager;
 import org.briarproject.api.messaging.PrivateMessageFactory;
 import org.briarproject.api.plugins.ConnectionRegistry;
 import org.briarproject.api.plugins.PluginManager;
-import org.briarproject.api.properties.TransportPropertyManager;
 import org.briarproject.api.settings.SettingsManager;
 import org.briarproject.plugins.AndroidPluginsModule;
 import org.briarproject.system.AndroidSystemModule;
@@ -91,8 +88,6 @@ public interface AndroidComponent extends CoreEagerSingletons {
 
 	PrivateMessageFactory privateMessageFactory();
 
-	TransportPropertyManager transportPropertyManager();
-
 	ForumManager forumManager();
 
 	ForumSharingManager forumSharingManager();
@@ -117,10 +112,6 @@ public interface AndroidComponent extends CoreEagerSingletons {
 
 	AndroidExecutor androidExecutor();
 
-	ForumPersistentData forumPersistentData();
-
-	BlogPersistentData blogPersistentData();
-
 	@IoExecutor
 	Executor ioExecutor();
 
diff --git a/briar-android/src/org/briarproject/android/AppModule.java b/briar-android/src/org/briarproject/android/AppModule.java
index 825e639c6c69ab442b1d85d388b2769e68920733..8f80ce0395841c0d5d1a5e81eb2d0c7f14a77831 100644
--- a/briar-android/src/org/briarproject/android/AppModule.java
+++ b/briar-android/src/org/briarproject/android/AppModule.java
@@ -4,8 +4,6 @@ import android.app.Application;
 
 import org.briarproject.android.api.AndroidNotificationManager;
 import org.briarproject.android.api.ReferenceManager;
-import org.briarproject.android.blogs.BlogPersistentData;
-import org.briarproject.android.forum.ForumPersistentData;
 import org.briarproject.api.crypto.CryptoComponent;
 import org.briarproject.api.crypto.PublicKey;
 import org.briarproject.api.crypto.SecretKey;
@@ -65,13 +63,13 @@ public class AppModule {
 	}
 
 	@Provides
-	public UiCallback provideUICallback() {
+	UiCallback provideUICallback() {
 		return uiCallback;
 	}
 
 	@Provides
 	@Singleton
-	public DatabaseConfig provideDatabaseConfig(Application app) {
+	DatabaseConfig provideDatabaseConfig(Application app) {
 		final File dir = app.getApplicationContext().getDir("db", MODE_PRIVATE);
 		return new DatabaseConfig() {
 
@@ -103,7 +101,7 @@ public class AppModule {
 
 	@Provides
 	@Singleton
-	public DevConfig provideDevConfig(final CryptoComponent crypto) {
+	DevConfig provideDevConfig(final CryptoComponent crypto) {
 		return new DevConfig() {
 
 			@Override
@@ -138,16 +136,4 @@ public class AppModule {
 		eventBus.addListener(notificationManager);
 		return notificationManager;
 	}
-
-	@Provides
-	@Singleton
-	ForumPersistentData provideForumPersistence() {
-		return new ForumPersistentData();
-	}
-
-	@Provides
-	@Singleton
-	BlogPersistentData provideBlogPersistence() {
-		return new BlogPersistentData();
-	}
 }
diff --git a/briar-android/src/org/briarproject/android/blogs/BlogActivity.java b/briar-android/src/org/briarproject/android/blogs/BlogActivity.java
index 35321f390a96ee09c356de2b294552cc812d9696..7519b46ab2c9d6b304085003d91a93d01cf4ebaf 100644
--- a/briar-android/src/org/briarproject/android/blogs/BlogActivity.java
+++ b/briar-android/src/org/briarproject/android/blogs/BlogActivity.java
@@ -21,7 +21,6 @@ import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
 
 import java.util.Collection;
-import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
@@ -38,8 +37,6 @@ public class BlogActivity extends BriarActivity implements BlogPostListener,
 	static final String IS_NEW_BLOG = "briar.IS_NEW_BLOG";
 
 	private static final String BLOG_PAGER_ADAPTER = "briar.BLOG_PAGER_ADAPTER";
-	private static final Logger LOG =
-			Logger.getLogger(BlogActivity.class.getName());
 
 	private ProgressBar progressBar;
 	private ViewPager pager;
diff --git a/briar-android/src/org/briarproject/android/blogs/BlogController.java b/briar-android/src/org/briarproject/android/blogs/BlogController.java
index a805c2d344e52c6295d60b90e7a79b563604583e..532d2dd2505dbb0cd75498f308522df0026e669f 100644
--- a/briar-android/src/org/briarproject/android/blogs/BlogController.java
+++ b/briar-android/src/org/briarproject/android/blogs/BlogController.java
@@ -3,18 +3,18 @@ package org.briarproject.android.blogs;
 import android.support.annotation.Nullable;
 
 import org.briarproject.android.controller.ActivityLifecycleController;
-import org.briarproject.android.controller.handler.UiResultHandler;
+import org.briarproject.android.controller.handler.ResultHandler;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
 
-import java.util.TreeSet;
+import java.util.SortedSet;
 
 public interface BlogController extends ActivityLifecycleController {
 
-	void loadBlog(final GroupId groupId, final boolean reload,
-			final UiResultHandler<Boolean> resultHandler);
+	void loadBlog(GroupId groupId, boolean reload,
+			ResultHandler<Boolean> resultHandler);
 
-	TreeSet<BlogPostItem> getBlogPosts();
+	SortedSet<BlogPostItem> getBlogPosts();
 
 	@Nullable
 	BlogPostItem getBlogPost(MessageId postId);
@@ -22,10 +22,10 @@ public interface BlogController extends ActivityLifecycleController {
 	@Nullable
 	MessageId getBlogPostId(int position);
 
-	void deleteBlog(final UiResultHandler<Boolean> resultHandler);
+	void deleteBlog(ResultHandler<Boolean> resultHandler);
 
 	interface BlogPostListener {
-		void onBlogPostAdded(final BlogPostItem post, final boolean local);
+		void onBlogPostAdded(BlogPostItem post, boolean local);
 	}
 
 }
diff --git a/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java b/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java
index d2898602c68dd664a4709cd761667b7d4e01a1dd..f34e63469e100c88d33d796faa766681d46b9444 100644
--- a/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java
@@ -4,7 +4,7 @@ import android.app.Activity;
 import android.support.annotation.Nullable;
 
 import org.briarproject.android.controller.DbControllerImpl;
-import org.briarproject.android.controller.handler.UiResultHandler;
+import org.briarproject.android.controller.handler.ResultHandler;
 import org.briarproject.api.blogs.Blog;
 import org.briarproject.api.blogs.BlogManager;
 import org.briarproject.api.blogs.BlogPostHeader;
@@ -19,6 +19,7 @@ import org.briarproject.api.sync.MessageId;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.logging.Logger;
 
@@ -39,10 +40,11 @@ public class BlogControllerImpl extends DbControllerImpl
 	protected volatile BlogManager blogManager;
 	@Inject
 	protected volatile EventBus eventBus;
-	@Inject
-	protected BlogPersistentData data;
 
 	private volatile BlogPostListener listener;
+	private volatile GroupId groupId = null;
+	// FIXME: This collection isn't thread-safe, isn't updated atomically
+	private volatile TreeSet<BlogPostItem> posts = null;
 
 	@Inject
 	BlogControllerImpl() {
@@ -71,22 +73,25 @@ public class BlogControllerImpl extends DbControllerImpl
 
 	@Override
 	public void onActivityDestroy() {
-		if (activity.isFinishing()) {
-			data.clearAll();
-		}
 	}
 
 	@Override
 	public void eventOccurred(Event e) {
 		if (e instanceof BlogPostAddedEvent) {
 			final BlogPostAddedEvent m = (BlogPostAddedEvent) e;
-			if (m.getGroupId().equals(data.getGroupId())) {
+			if (m.getGroupId().equals(groupId)) {
 				LOG.info("New blog post added");
+				if (posts == null) {
+					LOG.info("Posts have not loaded, yet");
+					// FIXME: Race condition, new post may not get loaded
+					return;
+				}
 				final BlogPostHeader header = m.getHeader();
+				// FIXME: Don't make blocking calls in event handlers
 				try {
 					final byte[] body = blogManager.getPostBody(header.getId());
 					final BlogPostItem post = new BlogPostItem(header, body);
-					data.addPost(post);
+					posts.add(post);
 					listener.onBlogPostAdded(post, m.isLocal());
 				} catch (DbException ex) {
 					if (LOG.isLoggable(WARNING))
@@ -95,7 +100,7 @@ public class BlogControllerImpl extends DbControllerImpl
 			}
 		} else if (e instanceof GroupRemovedEvent) {
 			GroupRemovedEvent s = (GroupRemovedEvent) e;
-			if (s.getGroup().getId().equals(data.getGroupId())) {
+			if (s.getGroup().getId().equals(groupId)) {
 				LOG.info("Blog removed");
 				activity.runOnUiThread(new Runnable() {
 					@Override
@@ -108,31 +113,29 @@ public class BlogControllerImpl extends DbControllerImpl
 	}
 
 	@Override
-	public void loadBlog(final GroupId groupId, final boolean reload,
-			final UiResultHandler<Boolean> resultHandler) {
+	public void loadBlog(final GroupId g, final boolean reload,
+			final ResultHandler<Boolean> resultHandler) {
 
-		LOG.info("Loading blog...");
 		runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
 				try {
-					if (reload || data.getGroupId() == null ||
-							!data.getGroupId().equals(groupId)) {
-						data.setGroupId(groupId);
+					if (reload || posts == null) {
+						groupId = g;
+						posts = new TreeSet<>();
 						// load blog posts
 						long now = System.currentTimeMillis();
-						Collection<BlogPostItem> posts = new ArrayList<>();
+						Collection<BlogPostItem> newPosts = new ArrayList<>();
 						Collection<BlogPostHeader> header =
-								blogManager.getPostHeaders(groupId);
+								blogManager.getPostHeaders(g);
 						for (BlogPostHeader h : header) {
 							byte[] body = blogManager.getPostBody(h.getId());
-							posts.add(new BlogPostItem(h, body));
+							newPosts.add(new BlogPostItem(h, body));
 						}
-						data.setPosts(posts);
+						posts.addAll(newPosts);
 						long duration = System.currentTimeMillis() - now;
 						if (LOG.isLoggable(INFO))
-							LOG.info("Post header load took " + duration +
-									" ms");
+							LOG.info("Loading blog took " + duration + " ms");
 					}
 					resultHandler.onResult(true);
 				} catch (DbException e) {
@@ -145,14 +148,16 @@ public class BlogControllerImpl extends DbControllerImpl
 	}
 
 	@Override
-	public TreeSet<BlogPostItem> getBlogPosts() {
-		return data.getBlogPosts();
+	@Nullable
+	public SortedSet<BlogPostItem> getBlogPosts() {
+		return posts;
 	}
 
 	@Override
 	@Nullable
 	public BlogPostItem getBlogPost(MessageId id) {
-		for (BlogPostItem item : getBlogPosts()) {
+		if (posts == null) return null;
+		for (BlogPostItem item : posts) {
 			if (item.getId().equals(id)) return item;
 		}
 		return null;
@@ -161,8 +166,9 @@ public class BlogControllerImpl extends DbControllerImpl
 	@Override
 	@Nullable
 	public MessageId getBlogPostId(int position) {
+		if (posts == null) return null;
 		int i = 0;
-		for (BlogPostItem post : getBlogPosts()) {
+		for (BlogPostItem post : posts) {
 			if (i == position) return post.getId();
 			i++;
 		}
@@ -170,16 +176,16 @@ public class BlogControllerImpl extends DbControllerImpl
 	}
 
 	@Override
-	public void deleteBlog(final UiResultHandler<Boolean> resultHandler) {
+	public void deleteBlog(final ResultHandler<Boolean> resultHandler) {
 		runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
-				if (data.getGroupId() == null) {
+				if (groupId == null) {
 					resultHandler.onResult(false);
 					return;
 				}
 				try {
-					Blog b = blogManager.getBlog(data.getGroupId());
+					Blog b = blogManager.getBlog(groupId);
 					blogManager.removeBlog(b);
 					resultHandler.onResult(true);
 				} catch (DbException e) {
diff --git a/briar-android/src/org/briarproject/android/blogs/BlogPersistentData.java b/briar-android/src/org/briarproject/android/blogs/BlogPersistentData.java
deleted file mode 100644
index a2834c809cd5afc0643be76ccdb7d6d5b3de1025..0000000000000000000000000000000000000000
--- a/briar-android/src/org/briarproject/android/blogs/BlogPersistentData.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.briarproject.android.blogs;
-
-import org.briarproject.api.sync.GroupId;
-
-import java.util.Collection;
-import java.util.TreeSet;
-
-import javax.inject.Inject;
-
-/**
- * This class is a singleton that defines the data that should persist, i.e.
- * still be present in memory after activity restarts. This class is not thread
- * safe.
- */
-public class BlogPersistentData {
-
-	private volatile GroupId groupId;
-	private volatile TreeSet<BlogPostItem> posts = new TreeSet<>();
-
-	public BlogPersistentData() {
-
-	}
-
-	public void setGroupId(GroupId groupId) {
-		this.groupId = groupId;
-	}
-
-	public GroupId getGroupId() {
-		return groupId;
-	}
-
-	public void setPosts(Collection<BlogPostItem> posts) {
-		this.posts.clear();
-		this.posts.addAll(posts);
-	}
-
-	void addPost(BlogPostItem post) {
-		posts.add(post);
-	}
-
-	TreeSet<BlogPostItem> getBlogPosts() {
-		return posts;
-	}
-
-	void clearAll() {
-		groupId = null;
-		posts.clear();
-	}
-}
diff --git a/briar-android/src/org/briarproject/android/forum/ForumActivity.java b/briar-android/src/org/briarproject/android/forum/ForumActivity.java
index 77f574f20f4a2a18f4471c01e0d9e1e63006fd06..f6a0c597f583591fa249157d91f12f8f36bfc13b 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumActivity.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumActivity.java
@@ -37,6 +37,7 @@ import org.briarproject.android.controller.handler.UiResultHandler;
 import org.briarproject.android.util.AndroidUtils;
 import org.briarproject.android.util.BriarRecyclerView;
 import org.briarproject.android.util.TrustIndicatorView;
+import org.briarproject.api.forum.Forum;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
 import org.briarproject.util.StringUtils;
@@ -117,7 +118,8 @@ public class ForumActivity extends BriarActivity implements
 					@Override
 					public void onResultUi(Boolean result) {
 						if (result) {
-							setTitle(forumController.getForumName());
+							Forum forum = forumController.getForum();
+							if (forum != null) setTitle(forum.getName());
 							forumAdapter = new ForumAdapter(
 									forumController.getForumEntries());
 							recyclerView.setAdapter(forumAdapter);
@@ -264,6 +266,7 @@ public class ForumActivity extends BriarActivity implements
 		String text = textInput.getText().toString();
 		if (text.trim().length() == 0)
 			return;
+		if (forumController.getForum() == null) return;
 		ForumEntry replyEntry = forumAdapter.getReplyEntry();
 		if (replyEntry == null) {
 			// root post
diff --git a/briar-android/src/org/briarproject/android/forum/ForumController.java b/briar-android/src/org/briarproject/android/forum/ForumController.java
index a3419b812f84edf39839f587186c2bcb2adff167..b492627e41e07a5ba18e7bd971484cc21cea91d1 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumController.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumController.java
@@ -1,7 +1,10 @@
 package org.briarproject.android.forum;
 
+import android.support.annotation.Nullable;
+
 import org.briarproject.android.controller.ActivityLifecycleController;
-import org.briarproject.android.controller.handler.UiResultHandler;
+import org.briarproject.android.controller.handler.ResultHandler;
+import org.briarproject.api.forum.Forum;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
 
@@ -10,17 +13,26 @@ import java.util.List;
 
 public interface ForumController extends ActivityLifecycleController {
 
-	void loadForum(GroupId groupId, UiResultHandler<Boolean> resultHandler);
-	String getForumName();
+	void loadForum(GroupId groupId, ResultHandler<Boolean> resultHandler);
+
+	@Nullable
+	Forum getForum();
+
 	List<ForumEntry> getForumEntries();
-	void unsubscribe(UiResultHandler<Boolean> resultHandler);
+
+	void unsubscribe(ResultHandler<Boolean> resultHandler);
+
 	void entryRead(ForumEntry forumEntry);
+
 	void entriesRead(Collection<ForumEntry> messageIds);
+
 	void createPost(byte[] body);
+
 	void createPost(byte[] body, MessageId parentId);
 
 	interface ForumPostListener {
 		void addLocalEntry(int index, ForumEntry entry);
+
 		void addForeignEntry(int index, ForumEntry entry);
 	}
 
diff --git a/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java b/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java
index b5e83f8f4fa1c317eefc0130c2aed156e0cc2f87..638074ca13753aa13438866160f96bbfe343144b 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java
@@ -1,10 +1,12 @@
 package org.briarproject.android.forum;
 
 import android.app.Activity;
+import android.support.annotation.Nullable;
 
 import org.briarproject.android.controller.DbControllerImpl;
-import org.briarproject.android.controller.handler.UiResultHandler;
+import org.briarproject.android.controller.handler.ResultHandler;
 import org.briarproject.api.FormatException;
+import org.briarproject.api.clients.MessageTree;
 import org.briarproject.api.crypto.CryptoComponent;
 import org.briarproject.api.crypto.CryptoExecutor;
 import org.briarproject.api.crypto.KeyParser;
@@ -15,15 +17,16 @@ import org.briarproject.api.event.EventBus;
 import org.briarproject.api.event.EventListener;
 import org.briarproject.api.event.ForumPostReceivedEvent;
 import org.briarproject.api.event.GroupRemovedEvent;
+import org.briarproject.api.forum.Forum;
 import org.briarproject.api.forum.ForumManager;
 import org.briarproject.api.forum.ForumPost;
 import org.briarproject.api.forum.ForumPostFactory;
 import org.briarproject.api.forum.ForumPostHeader;
-import org.briarproject.api.identity.Author;
 import org.briarproject.api.identity.IdentityManager;
 import org.briarproject.api.identity.LocalAuthor;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
+import org.briarproject.clients.MessageTreeImpl;
 import org.briarproject.util.StringUtils;
 
 import java.security.GeneralSecurityException;
@@ -31,7 +34,9 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.Stack;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
 import java.util.logging.Logger;
 
@@ -62,8 +67,14 @@ public class ForumControllerImpl extends DbControllerImpl
 	protected volatile EventBus eventBus;
 	@Inject
 	protected volatile IdentityManager identityManager;
-	@Inject
-	protected ForumPersistentData data;
+
+	private final Map<MessageId, byte[]> bodyCache = new ConcurrentHashMap<>();
+	private final MessageTree<ForumPostHeader> tree = new MessageTreeImpl<>();
+
+	private volatile LocalAuthor localAuthor = null;
+	private volatile Forum forum = null;
+	// FIXME: This collection isn't thread-safe, isn't updated atomically
+	private volatile List<ForumEntry> forumEntries = null;
 
 	private ForumPostListener listener;
 
@@ -95,22 +106,22 @@ public class ForumControllerImpl extends DbControllerImpl
 
 	@Override
 	public void onActivityDestroy() {
-		if (activity.isFinishing()) {
-			data.clearAll();
-		}
 	}
 
 	@Override
 	public void eventOccurred(Event e) {
+		if (forum == null) return;
+
 		if (e instanceof ForumPostReceivedEvent) {
 			ForumPostReceivedEvent pe = (ForumPostReceivedEvent) e;
-			if (pe.getGroupId().equals(data.getGroupId())) {
+			if (pe.getGroupId().equals(forum.getId())) {
 				LOG.info("Forum Post received, adding...");
+				// FIXME: Don't make blocking calls in event handlers
 				addNewPost(pe.getForumPostHeader());
 			}
 		} else if (e instanceof GroupRemovedEvent) {
 			GroupRemovedEvent s = (GroupRemovedEvent) e;
-			if (s.getGroup().getId().equals(data.getGroupId())) {
+			if (s.getGroup().getId().equals(forum.getId())) {
 				LOG.info("Forum removed");
 				activity.runOnUiThread(new Runnable() {
 					@Override
@@ -123,28 +134,29 @@ public class ForumControllerImpl extends DbControllerImpl
 	}
 
 	private void addNewPost(final ForumPostHeader h) {
-		if (data == null) return;
+		if (forum == null) return;
 		runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
-				data.addHeader(h);
-				data.clearForumEntries();
-
-				try {
-					byte[] body = forumManager.getPostBody(h.getId());
-					data.addBody(h.getId(), body);
-				} catch (DbException e) {
-					if (LOG.isLoggable(WARNING))
-						LOG.log(WARNING, e.toString(), e);
+				if (!bodyCache.containsKey(h.getId())) {
+					try {
+						byte[] body = forumManager.getPostBody(h.getId());
+						bodyCache.put(h.getId(), body);
+					} catch (DbException e) {
+						if (LOG.isLoggable(WARNING))
+							LOG.log(WARNING, e.toString(), e);
+						return;
+					}
 				}
 
-				Author a = data.getLocalAuthor();
+				tree.add(h);
+				forumEntries = null;
 				// FIXME we should not need to calculate the index here
 				//       the index is essentially stored in two different locations
 				int i = 0;
 				for (ForumEntry entry : getForumEntries()) {
 					if (entry.getMessageId().equals(h.getId())) {
-						if (a != null && a.equals(h.getAuthor())) {
+						if (localAuthor != null && localAuthor.equals(h.getAuthor())) {
 							addLocalEntry(i, entry);
 						} else {
 							addForeignEntry(i, entry);
@@ -156,31 +168,29 @@ public class ForumControllerImpl extends DbControllerImpl
 		});
 	}
 
-	private void loadAuthor() throws DbException {
-		Collection<LocalAuthor> localAuthors =
-				identityManager.getLocalAuthors();
-
-		for (LocalAuthor author : localAuthors) {
-			if (author == null)
-				continue;
-			data.setLocalAuthor(author);
-			break;
-		}
-	}
-
+	/**
+	 * This should only be run from the DbThread.
+	 * @throws DbException
+	 */
 	private void loadPosts() throws DbException {
+		if (forum == null)
+			throw new RuntimeException("Forum has not been initialized");
+
+		// Get Headers
 		long now = System.currentTimeMillis();
 		Collection<ForumPostHeader> headers =
-				forumManager.getPostHeaders(data.getGroupId());
-		data.addHeaders(headers);
+				forumManager.getPostHeaders(forum.getId());
+		tree.add(headers);
 		long duration = System.currentTimeMillis() - now;
 		if (LOG.isLoggable(INFO))
 			LOG.info("Loading headers took " + duration + " ms");
+
+		// Get Bodies
 		now = System.currentTimeMillis();
 		for (ForumPostHeader header : headers) {
-			if (data.getBody(header.getId()) == null) {
+			if (!bodyCache.containsKey(header.getId())) {
 				byte[] body = forumManager.getPostBody(header.getId());
-				data.addBody(header.getId(), body);
+				bodyCache.put(header.getId(), body);
 			}
 		}
 		duration = System.currentTimeMillis() - now;
@@ -190,29 +200,32 @@ public class ForumControllerImpl extends DbControllerImpl
 
 	@Override
 	public void loadForum(final GroupId groupId,
-			final UiResultHandler<Boolean> resultHandler) {
-		LOG.info("Loading forum...");
-
+			final ResultHandler<Boolean> resultHandler) {
 		runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
+				LOG.info("Loading forum...");
 				try {
-					if (data.getGroupId() == null ||
-							!data.getGroupId().equals(groupId)) {
-						data.clearAll();
-						data.setGroupId(groupId);
+					if (forum == null) {
+						// Get Forum
 						long now = System.currentTimeMillis();
-						data.setForum(forumManager.getForum(groupId));
+						forum = forumManager.getForum(groupId);
 						long duration = System.currentTimeMillis() - now;
 						if (LOG.isLoggable(INFO))
 							LOG.info("Loading forum took " + duration +
 									" ms");
+
+						// Get First Identity
 						now = System.currentTimeMillis();
-						loadAuthor();
+						localAuthor =
+								identityManager.getLocalAuthors().iterator()
+										.next();
 						duration = System.currentTimeMillis() - now;
 						if (LOG.isLoggable(INFO))
 							LOG.info("Loading author took " + duration +
 									" ms");
+
+						// Get Forum Posts and Bodies
 						loadPosts();
 					}
 					resultHandler.onResult(true);
@@ -223,21 +236,21 @@ public class ForumControllerImpl extends DbControllerImpl
 				}
 			}
 		});
-
 	}
 
 	@Override
-	public String getForumName() {
-		return data.getForum() == null ? null : data.getForum().getName();
+	@Nullable
+	public Forum getForum() {
+		return forum;
 	}
 
 	@Override
 	public List<ForumEntry> getForumEntries() {
-		if (data.getForumEntries() != null) {
-			return data.getForumEntries();
+		if (forumEntries != null) {
+			return forumEntries;
 		}
-		Collection<ForumPostHeader> headers = data.getHeaders();
-		List<ForumEntry> forumEntries = new ArrayList<>();
+		Collection<ForumPostHeader> headers = getHeaders();
+		List<ForumEntry> entries = new ArrayList<>();
 		Stack<MessageId> idStack = new Stack<>();
 
 		for (ForumPostHeader h : headers) {
@@ -251,21 +264,23 @@ public class ForumControllerImpl extends DbControllerImpl
 					idStack.pop();
 				} while (!h.getParentId().equals(idStack.peek()));
 			}
-			forumEntries.add(new ForumEntry(h,
-					StringUtils.fromUtf8(data.getBody(h.getId())),
-					idStack.size()));
+			byte[] body = bodyCache.get(h.getId());
+			entries.add(new ForumEntry(h, StringUtils.fromUtf8(body),
+						idStack.size()));
 		}
-		data.setForumEntries(forumEntries);
-		return forumEntries;
+		forumEntries = entries;
+		return entries;
 	}
 
 	@Override
-	public void unsubscribe(final UiResultHandler<Boolean> resultHandler) {
+	public void unsubscribe(final ResultHandler<Boolean> resultHandler) {
+		if (forum == null) return;
 		runOnDbThread(new Runnable() {
+			@Override
 			public void run() {
 				try {
 					long now = System.currentTimeMillis();
-					forumManager.removeForum(data.getForum());
+					forumManager.removeForum(forum);
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Removing forum took " + duration + " ms");
@@ -287,6 +302,7 @@ public class ForumControllerImpl extends DbControllerImpl
 	@Override
 	public void entriesRead(final Collection<ForumEntry> forumEntries) {
 		runOnDbThread(new Runnable() {
+			@Override
 			public void run() {
 				try {
 					long now = System.currentTimeMillis();
@@ -312,10 +328,11 @@ public class ForumControllerImpl extends DbControllerImpl
 	@Override
 	public void createPost(final byte[] body, final MessageId parentId) {
 		cryptoExecutor.execute(new Runnable() {
+			@Override
 			public void run() {
 				long timestamp = System.currentTimeMillis();
 				long newestTimeStamp = 0;
-				Collection<ForumPostHeader> headers = data.getHeaders();
+				Collection<ForumPostHeader> headers = getHeaders();
 				if (headers != null) {
 					for (ForumPostHeader h : headers) {
 						if (h.getTimestamp() > newestTimeStamp)
@@ -329,16 +346,18 @@ public class ForumControllerImpl extends DbControllerImpl
 				ForumPost p;
 				try {
 					KeyParser keyParser = crypto.getSignatureKeyParser();
-					byte[] b = data.getLocalAuthor().getPrivateKey();
+					byte[] b = localAuthor.getPrivateKey();
 					PrivateKey authorKey = keyParser.parsePrivateKey(b);
 					p = forumPostFactory.createPseudonymousPost(
-							data.getGroupId(), timestamp, parentId,
-							data.getLocalAuthor(), "text/plain", body,
+							forum.getId(), timestamp, parentId,
+							localAuthor, "text/plain", body,
 							authorKey);
 				} catch (GeneralSecurityException | FormatException e) {
 					throw new RuntimeException(e);
 				}
+				bodyCache.put(p.getMessage().getId(), body);
 				storePost(p);
+				// FIXME: Don't make DB calls on the crypto executor
 				addNewPost(p);
 			}
 		});
@@ -364,6 +383,7 @@ public class ForumControllerImpl extends DbControllerImpl
 
 	private void storePost(final ForumPost p) {
 		runOnDbThread(new Runnable() {
+			@Override
 			public void run() {
 				try {
 					long now = System.currentTimeMillis();
@@ -388,4 +408,8 @@ public class ForumControllerImpl extends DbControllerImpl
 		addNewPost(h);
 	}
 
+	private Collection<ForumPostHeader> getHeaders() {
+		return tree.depthFirstOrder();
+	}
+
 }
diff --git a/briar-android/src/org/briarproject/android/forum/ForumPersistentData.java b/briar-android/src/org/briarproject/android/forum/ForumPersistentData.java
deleted file mode 100644
index 6464be24ead03476e301674648cee386da43b0df..0000000000000000000000000000000000000000
--- a/briar-android/src/org/briarproject/android/forum/ForumPersistentData.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package org.briarproject.android.forum;
-
-import org.briarproject.api.clients.MessageTree;
-import org.briarproject.api.forum.Forum;
-import org.briarproject.api.forum.ForumPostHeader;
-import org.briarproject.api.identity.LocalAuthor;
-import org.briarproject.api.sync.GroupId;
-import org.briarproject.api.sync.MessageId;
-import org.briarproject.clients.MessageTreeImpl;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * This class is a singleton that defines the data that should persist, i.e.
- * still be present in memory after activity restarts. This class is not thread
- * safe.
- */
-public class ForumPersistentData {
-
-	private volatile MessageTree<ForumPostHeader> tree =
-			new MessageTreeImpl<>();
-	private volatile Map<MessageId, byte[]> bodyCache = new HashMap<>();
-	private volatile LocalAuthor localAuthor;
-	private volatile Forum forum;
-	private volatile GroupId groupId;
-	private List<ForumEntry> forumEntries;
-
-	void clearAll() {
-		clearForumEntries();
-		tree.clear();
-		bodyCache.clear();
-		localAuthor = null;
-		forum = null;
-		groupId = null;
-	}
-
-	void clearForumEntries() {
-		forumEntries = null;
-	}
-
-	void addHeaders(Collection<ForumPostHeader> headers) {
-		tree.add(headers);
-	}
-
-	void addHeader(ForumPostHeader header) {
-		tree.add(header);
-	}
-
-	public Collection<ForumPostHeader> getHeaders() {
-		return tree.depthFirstOrder();
-	}
-
-	void addBody(MessageId messageId, byte[] body) {
-		bodyCache.put(messageId, body);
-	}
-
-	byte[] getBody(MessageId messageId) {
-		return bodyCache.get(messageId);
-	}
-
-	public LocalAuthor getLocalAuthor() {
-		return localAuthor;
-	}
-
-	public void setLocalAuthor(
-			LocalAuthor localAuthor) {
-		this.localAuthor = localAuthor;
-	}
-
-	public Forum getForum() {
-		return forum;
-	}
-
-	public void setForum(Forum forum) {
-		this.forum = forum;
-	}
-
-	public GroupId getGroupId() {
-		return groupId;
-	}
-
-	public void setGroupId(GroupId groupId) {
-		this.groupId = groupId;
-	}
-
-	List<ForumEntry> getForumEntries() {
-		return forumEntries;
-	}
-
-	void setForumEntries(List<ForumEntry> forumEntries) {
-		this.forumEntries = forumEntries;
-	}
-}
diff --git a/briar-android/src/org/briarproject/android/forum/ForumTestControllerImpl.java b/briar-android/src/org/briarproject/android/forum/ForumTestControllerImpl.java
index 2aef2ae5e121fe61e60789800aea97ac75e51a0b..8f90062415305e34021dc4ad87c8f8294245f858 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumTestControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumTestControllerImpl.java
@@ -1,7 +1,9 @@
 package org.briarproject.android.forum;
 
+import org.briarproject.android.controller.handler.ResultHandler;
 import org.briarproject.android.controller.handler.UiResultHandler;
 import org.briarproject.api.UniqueId;
+import org.briarproject.api.forum.Forum;
 import org.briarproject.api.identity.AuthorId;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
@@ -63,7 +65,7 @@ public class ForumTestControllerImpl implements ForumController {
 	private ForumEntry[] forumEntries;
 
 	@Inject
-	public ForumTestControllerImpl() {
+	ForumTestControllerImpl() {
 
 	}
 
@@ -94,7 +96,7 @@ public class ForumTestControllerImpl implements ForumController {
 
 	@Override
 	public void loadForum(GroupId groupId,
-			UiResultHandler<Boolean> resultHandler) {
+			ResultHandler<Boolean> resultHandler) {
 		SecureRandom random = new SecureRandom();
 		forumEntries = new ForumEntry[100];
 		// string cut off index
@@ -124,14 +126,14 @@ public class ForumTestControllerImpl implements ForumController {
 	}
 
 	@Override
-	public String getForumName() {
-		return "SAGA";
+	public Forum getForum() {
+		return null;
 	}
 
 	@Override
 	public List<ForumEntry> getForumEntries() {
 		return forumEntries == null ? null :
-				new ArrayList<ForumEntry>(Arrays.asList(forumEntries));
+				new ArrayList<>(Arrays.asList(forumEntries));
 	}
 
 	@Override