diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java
index 1953756c626b08f4e7b8b1b15334cbaaf2b1caff..7c7b62c63c4cb0f969b8431f5665d0eb88587971 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java
@@ -2,6 +2,7 @@ package org.briarproject.briar.android.activity;
 
 import android.os.Bundle;
 import android.os.IBinder;
+import android.support.annotation.UiThread;
 import android.support.v7.app.AppCompatActivity;
 import android.view.View;
 import android.view.inputmethod.InputMethodManager;
@@ -118,6 +119,7 @@ public abstract class BaseActivity extends AppCompatActivity
 		((InputMethodManager) o).hideSoftInputFromWindow(token, 0);
 	}
 
+	@UiThread
 	public void handleDbException(DbException e) {
 		supportFinishAfterTransition();
 	}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/ConversationActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/ConversationActivity.java
index 38041a6924e0a072f65363f5951f2c9d0d0e566e..1d807dcddb16d697b458a3288af066a1785d4615 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/contact/ConversationActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/ConversationActivity.java
@@ -79,6 +79,8 @@ import org.briarproject.briar.api.sharing.InvitationRequest;
 import org.briarproject.briar.api.sharing.InvitationResponse;
 import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent;
 import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent;
+import org.thoughtcrime.securesms.components.util.FutureTaskListener;
+import org.thoughtcrime.securesms.components.util.ListenableFutureTask;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -86,8 +88,10 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Logger;
 
 import javax.annotation.Nullable;
@@ -139,6 +143,18 @@ public class ConversationActivity extends BriarActivity
 	private BriarRecyclerView list;
 	private TextInputView textInputView;
 
+	private final ListenableFutureTask<String> contactNameTask =
+			new ListenableFutureTask<>(new Callable<String>() {
+				@Override
+				public String call() throws Exception {
+					Contact c = contactManager.getContact(contactId);
+					contactName = c.getAuthor().getName();
+					return c.getAuthor().getName();
+				}
+			});
+	private final AtomicBoolean contactNameTaskStarted =
+			new AtomicBoolean(false);
+
 	// Fields that are accessed from background threads must be volatile
 	@Inject
 	volatile ContactManager contactManager;
@@ -160,8 +176,11 @@ public class ConversationActivity extends BriarActivity
 	volatile GroupInvitationManager groupInvitationManager;
 
 	private volatile ContactId contactId;
+	@Nullable
 	private volatile String contactName;
+	@Nullable
 	private volatile AuthorId contactAuthorId;
+	@Nullable
 	private volatile GroupId messagingGroupId;
 
 	@SuppressWarnings("ConstantConditions")
@@ -223,8 +242,8 @@ public class ConversationActivity extends BriarActivity
 		eventBus.addListener(this);
 		notificationManager.blockContactNotification(contactId);
 		notificationManager.clearContactNotification(contactId);
-		loadContactDetails();
-		loadMessages();
+		displayContactOnlineStatus();
+		loadContactDetailsAndMessages();
 		list.startPeriodicUpdate();
 	}
 
@@ -269,7 +288,7 @@ public class ConversationActivity extends BriarActivity
 		}
 	}
 
-	private void loadContactDetails() {
+	private void loadContactDetailsAndMessages() {
 		runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
@@ -283,6 +302,7 @@ public class ConversationActivity extends BriarActivity
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Loading contact took " + duration + " ms");
+					loadMessages();
 					displayContactDetails();
 				} catch (NoSuchContactException e) {
 					finishOnUiThread();
@@ -298,10 +318,18 @@ public class ConversationActivity extends BriarActivity
 		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
+				//noinspection ConstantConditions
 				toolbarAvatar.setImageDrawable(
 						new IdenticonDrawable(contactAuthorId.getBytes()));
 				toolbarTitle.setText(contactName);
+			}
+		});
+	}
 
+	private void displayContactOnlineStatus() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
+			@Override
+			public void run() {
 				if (connectionRegistry.isConnected(contactId)) {
 					toolbarStatus.setImageDrawable(ContextCompat
 							.getDrawable(ConversationActivity.this,
@@ -341,7 +369,8 @@ public class ConversationActivity extends BriarActivity
 							groupInvitationManager
 									.getInvitationMessages(contactId);
 					List<InvitationMessage> invitations = new ArrayList<>(
-							forumInvitations.size() + blogInvitations.size());
+							forumInvitations.size() + blogInvitations.size() +
+									groupInvitations.size());
 					invitations.addAll(forumInvitations);
 					invitations.addAll(blogInvitations);
 					invitations.addAll(groupInvitations);
@@ -384,6 +413,12 @@ public class ConversationActivity extends BriarActivity
 		});
 	}
 
+	/**
+	 * Creates ConversationItems from headers loaded from the database.
+	 *
+	 * Attention: Call this only after contactName has been initialized.
+	 */
+	@SuppressWarnings("ConstantConditions")
 	private List<ConversationItem> createItems(
 			Collection<PrivateMessageHeader> headers,
 			Collection<IntroductionMessage> introductions,
@@ -462,18 +497,6 @@ public class ConversationActivity extends BriarActivity
 		});
 	}
 
-	private void addConversationItem(final ConversationItem item) {
-		runOnUiThreadUnlessDestroyed(new Runnable() {
-			@Override
-			public void run() {
-				adapter.incrementRevision();
-				adapter.add(item);
-				// Scroll to the bottom
-				list.scrollToPosition(adapter.getItemCount() - 1);
-			}
-		});
-	}
-
 	@Override
 	public void eventOccurred(Event e) {
 		if (e instanceof ContactRemovedEvent) {
@@ -506,13 +529,13 @@ public class ConversationActivity extends BriarActivity
 			ContactConnectedEvent c = (ContactConnectedEvent) e;
 			if (c.getContactId().equals(contactId)) {
 				LOG.info("Contact connected");
-				displayContactDetails();
+				displayContactOnlineStatus();
 			}
 		} else if (e instanceof ContactDisconnectedEvent) {
 			ContactDisconnectedEvent c = (ContactDisconnectedEvent) e;
 			if (c.getContactId().equals(contactId)) {
 				LOG.info("Contact disconnected");
-				displayContactDetails();
+				displayContactOnlineStatus();
 			}
 		} else if (e instanceof IntroductionRequestReceivedEvent) {
 			IntroductionRequestReceivedEvent event =
@@ -520,9 +543,7 @@ public class ConversationActivity extends BriarActivity
 			if (event.getContactId().equals(contactId)) {
 				LOG.info("Introduction request received, adding...");
 				IntroductionRequest ir = event.getIntroductionRequest();
-				ConversationItem item =
-						ConversationItem.from(this, contactName, ir);
-				addConversationItem(item);
+				handleIntroductionRequest(ir);
 			}
 		} else if (e instanceof IntroductionResponseReceivedEvent) {
 			IntroductionResponseReceivedEvent event =
@@ -530,9 +551,7 @@ public class ConversationActivity extends BriarActivity
 			if (event.getContactId().equals(contactId)) {
 				LOG.info("Introduction response received, adding...");
 				IntroductionResponse ir = event.getIntroductionResponse();
-				ConversationItem item =
-						ConversationItem.from(this, contactName, ir);
-				addConversationItem(item);
+				handleIntroductionResponse(ir);
 			}
 		} else if (e instanceof InvitationRequestReceivedEvent) {
 			InvitationRequestReceivedEvent event =
@@ -540,9 +559,7 @@ public class ConversationActivity extends BriarActivity
 			if (event.getContactId().equals(contactId)) {
 				LOG.info("Invitation received, adding...");
 				InvitationRequest ir = event.getRequest();
-				ConversationItem item =
-						ConversationItem.from(this, contactName, ir);
-				addConversationItem(item);
+				handleInvitationRequest(ir);
 			}
 		} else if (e instanceof InvitationResponseReceivedEvent) {
 			InvitationResponseReceivedEvent event =
@@ -550,13 +567,127 @@ public class ConversationActivity extends BriarActivity
 			if (event.getContactId().equals(contactId)) {
 				LOG.info("Invitation response received, adding...");
 				InvitationResponse ir = event.getResponse();
-				ConversationItem item =
-						ConversationItem.from(this, contactName, ir);
-				addConversationItem(item);
+				handleInvitationResponse(ir);
 			}
 		}
 	}
 
+	private void addConversationItem(final ConversationItem item) {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
+			@Override
+			public void run() {
+				adapter.incrementRevision();
+				adapter.add(item);
+				// Scroll to the bottom
+				list.scrollToPosition(adapter.getItemCount() - 1);
+			}
+		});
+	}
+
+	private void handleIntroductionRequest(final IntroductionRequest m) {
+		getContactNameTask().addListener(new FutureTaskListener<String>() {
+			@Override
+			public void onSuccess(final String contactName) {
+				runOnUiThreadUnlessDestroyed(new Runnable() {
+					@Override
+					public void run() {
+						ConversationItem item = ConversationItem
+								.from(ConversationActivity.this, contactName,
+										m);
+						addConversationItem(item);
+					}
+				});
+			}
+			@Override
+			public void onFailure(final Throwable exception) {
+				runOnUiThreadUnlessDestroyed(new Runnable() {
+					@Override
+					public void run() {
+						handleDbException((DbException) exception);
+					}
+				});
+			}
+		});
+	}
+
+	private void handleIntroductionResponse(final IntroductionResponse m) {
+		getContactNameTask().addListener(new FutureTaskListener<String>() {
+			@Override
+			public void onSuccess(final String contactName) {
+				runOnUiThreadUnlessDestroyed(new Runnable() {
+					@Override
+					public void run() {
+						ConversationItem item = ConversationItem
+								.from(ConversationActivity.this, contactName,
+										m);
+						addConversationItem(item);
+					}
+				});
+			}
+			@Override
+			public void onFailure(final Throwable exception) {
+				runOnUiThreadUnlessDestroyed(new Runnable() {
+					@Override
+					public void run() {
+						handleDbException((DbException) exception);
+					}
+				});
+			}
+		});
+	}
+
+	private void handleInvitationRequest(final InvitationRequest m) {
+		getContactNameTask().addListener(new FutureTaskListener<String>() {
+			@Override
+			public void onSuccess(final String contactName) {
+				runOnUiThreadUnlessDestroyed(new Runnable() {
+					@Override
+					public void run() {
+						ConversationItem item = ConversationItem
+								.from(ConversationActivity.this, contactName,
+										m);
+						addConversationItem(item);
+					}
+				});
+			}
+			@Override
+			public void onFailure(final Throwable exception) {
+				runOnUiThreadUnlessDestroyed(new Runnable() {
+					@Override
+					public void run() {
+						handleDbException((DbException) exception);
+					}
+				});
+			}
+		});
+	}
+
+	private void handleInvitationResponse(final InvitationResponse m) {
+		getContactNameTask().addListener(new FutureTaskListener<String>() {
+			@Override
+			public void onSuccess(final String contactName) {
+				runOnUiThreadUnlessDestroyed(new Runnable() {
+					@Override
+					public void run() {
+						ConversationItem item = ConversationItem
+								.from(ConversationActivity.this, contactName,
+										m);
+						addConversationItem(item);
+					}
+				});
+			}
+			@Override
+			public void onFailure(final Throwable exception) {
+				runOnUiThreadUnlessDestroyed(new Runnable() {
+					@Override
+					public void run() {
+						handleDbException((DbException) exception);
+					}
+				});
+			}
+		});
+	}
+
 	private void markMessages(final Collection<MessageId> messageIds,
 			final boolean sent, final boolean seen) {
 		runOnUiThreadUnlessDestroyed(new Runnable() {
@@ -617,6 +748,7 @@ public class ConversationActivity extends BriarActivity
 			@Override
 			public void run() {
 				try {
+					//noinspection ConstantConditions init in loadGroupId()
 					storeMessage(privateMessageFactory.createPrivateMessage(
 							messagingGroupId, timestamp, body), body);
 				} catch (FormatException e) {
@@ -848,7 +980,6 @@ public class ConversationActivity extends BriarActivity
 					if (LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
 				}
-
 			}
 		});
 	}
@@ -919,4 +1050,10 @@ public class ConversationActivity extends BriarActivity
 		});
 	}
 
+	private ListenableFutureTask<String> getContactNameTask() {
+		if (!contactNameTaskStarted.getAndSet(true))
+			runOnDbThread(contactNameTask);
+		return contactNameTask;
+	}
+
 }