From cb983f02c278a45a327a71d0b5b5182cd661fbf3 Mon Sep 17 00:00:00 2001
From: akwizgran <akwizgran@users.sourceforge.net>
Date: Thu, 29 Sep 2016 14:52:00 +0100
Subject: [PATCH] Always check whether context has been destroyed.

---
 .../briarproject/android/ActivityModule.java  | 29 +++++--------
 .../briarproject/android/BaseActivity.java    | 16 ++++---
 .../briarproject/android/BriarActivity.java   |  2 +-
 .../android/BriarFragmentActivity.java        | 10 ++---
 .../android/DestroyableActivity.java          | 12 ------
 .../android/DestroyableContext.java           |  6 +++
 .../android/NavDrawerActivity.java            | 17 +++-----
 .../android/blogs/BaseController.java         |  7 ++-
 .../android/blogs/BaseControllerImpl.java     | 20 ++++-----
 .../android/blogs/BasePostFragment.java       |  2 +-
 .../android/blogs/BasePostPagerFragment.java  |  6 +++
 .../android/blogs/BlogControllerImpl.java     |  9 ++--
 .../android/blogs/BlogFragment.java           | 12 ++++--
 .../android/blogs/BlogPostPagerFragment.java  |  3 +-
 .../android/blogs/FeedFragment.java           |  5 +++
 .../android/blogs/FeedPostPagerFragment.java  |  1 -
 .../android/blogs/ReblogFragment.java         | 13 +-----
 .../android/blogs/RssFeedImportActivity.java  |  9 ++--
 .../android/blogs/RssFeedManageActivity.java  |  7 +--
 .../android/blogs/WriteBlogPostActivity.java  |  8 ++--
 .../android/contact/ContactListFragment.java  | 32 ++++++--------
 .../android/contact/ConversationActivity.java | 34 +++++++--------
 .../ActivityLifecycleController.java          |  5 ++-
 .../controller/BriarControllerImpl.java       | 10 ++---
 .../controller/NavDrawerController.java       |  2 -
 .../controller/NavDrawerControllerImpl.java   | 25 ++++-------
 .../controller/TransportStateListener.java    |  3 +-
 .../handler/UiResultExceptionHandler.java     | 16 +++----
 .../controller/handler/UiResultHandler.java   | 12 +++---
 .../android/forum/CreateForumActivity.java    |  2 +-
 .../android/forum/ForumActivity.java          | 11 +++--
 .../android/forum/ForumController.java        |  9 +++-
 .../android/forum/ForumControllerImpl.java    | 22 +++++-----
 .../android/forum/ForumListFragment.java      | 19 ++++----
 .../android/fragment/BaseFragment.java        | 21 ++++-----
 .../android/fragment/SettingsFragment.java    | 15 +++----
 .../introduction/ContactChooserFragment.java  | 15 ++-----
 .../IntroductionMessageFragment.java          | 17 +++-----
 .../invitation/AddContactActivity.java        | 43 +++++++++++++++----
 .../android/keyagreement/IntroFragment.java   |  7 +--
 .../keyagreement/KeyAgreementActivity.java    |  8 ++--
 .../keyagreement/ShowQrCodeFragment.java      | 36 +++++++---------
 .../sharing/ContactSelectorFragment.java      | 15 ++-----
 .../android/sharing/InvitationsActivity.java  |  4 +-
 .../sharing/ShareBlogMessageFragment.java     | 11 ++++-
 .../sharing/ShareForumMessageFragment.java    | 11 ++++-
 .../android/sharing/ShareMessageFragment.java | 21 +--------
 .../sharing/SharingStatusActivity.java        | 12 +++---
 .../android/view/TextInputView.java           | 18 ++++----
 49 files changed, 310 insertions(+), 340 deletions(-)
 delete mode 100644 briar-android/src/org/briarproject/android/DestroyableActivity.java
 create mode 100644 briar-android/src/org/briarproject/android/DestroyableContext.java

diff --git a/briar-android/src/org/briarproject/android/ActivityModule.java b/briar-android/src/org/briarproject/android/ActivityModule.java
index ff40912c11..21a7d35ef0 100644
--- a/briar-android/src/org/briarproject/android/ActivityModule.java
+++ b/briar-android/src/org/briarproject/android/ActivityModule.java
@@ -20,7 +20,6 @@ import org.briarproject.android.controller.PasswordController;
 import org.briarproject.android.controller.PasswordControllerImpl;
 import org.briarproject.android.controller.SetupController;
 import org.briarproject.android.controller.SetupControllerImpl;
-import org.briarproject.android.controller.TransportStateListener;
 import org.briarproject.android.forum.ForumController;
 import org.briarproject.android.forum.ForumControllerImpl;
 
@@ -52,27 +51,27 @@ public class ActivityModule {
 
 	@ActivityScope
 	@Provides
-	protected SetupController provideSetupController(
+	SetupController provideSetupController(
 			SetupControllerImpl setupControllerImpl) {
 		return setupControllerImpl;
 	}
 
 	@ActivityScope
 	@Provides
-	protected ConfigController provideConfigController(
+	ConfigController provideConfigController(
 			ConfigControllerImpl configControllerImpl) {
 		return configControllerImpl;
 	}
 
 	@ActivityScope
 	@Provides
-	protected SharedPreferences provideSharedPreferences(Activity activity) {
+	SharedPreferences provideSharedPreferences(Activity activity) {
 		return activity.getSharedPreferences("db", Context.MODE_PRIVATE);
 	}
 
 	@ActivityScope
 	@Provides
-	protected PasswordController providePasswordController(
+	PasswordController providePasswordController(
 			PasswordControllerImpl passwordControllerImpl) {
 		return passwordControllerImpl;
 	}
@@ -87,8 +86,7 @@ public class ActivityModule {
 
 	@ActivityScope
 	@Provides
-	protected DbController provideDBController(
-			DbControllerImpl dbController) {
+	DbController provideDBController(DbControllerImpl dbController) {
 		return dbController;
 	}
 
@@ -109,26 +107,21 @@ public class ActivityModule {
 
 	@ActivityScope
 	@Provides
-	protected FeedController provideFeedController(
-			FeedControllerImpl feedController) {
+	FeedController provideFeedController(FeedControllerImpl feedController) {
 		return feedController;
 	}
 
 	@ActivityScope
 	@Provides
-	protected NavDrawerController provideNavDrawerController(
-			NavDrawerControllerImpl navDrawerControllerImpl) {
-		activity.addLifecycleController(navDrawerControllerImpl);
-		if (activity instanceof TransportStateListener) {
-			navDrawerControllerImpl.setTransportListener(
-					(TransportStateListener) activity);
-		}
-		return navDrawerControllerImpl;
+	NavDrawerController provideNavDrawerController(
+			NavDrawerControllerImpl navDrawerController) {
+		activity.addLifecycleController(navDrawerController);
+		return navDrawerController;
 	}
 
 	@ActivityScope
 	@Provides
-	protected BriarServiceConnection provideBriarServiceConnection() {
+	BriarServiceConnection provideBriarServiceConnection() {
 		return new BriarServiceConnection();
 	}
 
diff --git a/briar-android/src/org/briarproject/android/BaseActivity.java b/briar-android/src/org/briarproject/android/BaseActivity.java
index 92f31ef7e5..5ee0bbee89 100644
--- a/briar-android/src/org/briarproject/android/BaseActivity.java
+++ b/briar-android/src/org/briarproject/android/BaseActivity.java
@@ -2,7 +2,6 @@ package org.briarproject.android;
 
 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;
@@ -18,7 +17,7 @@ import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
 import static org.briarproject.android.TestingConstants.PREVENT_SCREENSHOTS;
 
 public abstract class BaseActivity extends AppCompatActivity
-		implements DestroyableActivity {
+		implements DestroyableContext {
 
 	protected ActivityComponent activityComponent;
 
@@ -49,7 +48,7 @@ public abstract class BaseActivity extends AppCompatActivity
 		injectActivity(activityComponent);
 
 		for (ActivityLifecycleController alc : lifecycleControllers) {
-			alc.onActivityCreate();
+			alc.onActivityCreate(this);
 		}
 	}
 
@@ -87,9 +86,14 @@ public abstract class BaseActivity extends AppCompatActivity
 		}
 	}
 
-	@UiThread
-	public boolean hasBeenDestroyed() {
-		return destroyed;
+	@Override
+	public void runOnUiThreadUnlessDestroyed(final Runnable r) {
+		runOnUiThread(new Runnable() {
+			@Override
+			public void run() {
+				if (!destroyed && !isFinishing()) r.run();
+			}
+		});
 	}
 
 	public void showSoftKeyboardForced(View view) {
diff --git a/briar-android/src/org/briarproject/android/BriarActivity.java b/briar-android/src/org/briarproject/android/BriarActivity.java
index d13dda3826..49dc574a85 100644
--- a/briar-android/src/org/briarproject/android/BriarActivity.java
+++ b/briar-android/src/org/briarproject/android/BriarActivity.java
@@ -94,7 +94,7 @@ public abstract class BriarActivity extends BaseActivity {
 
 	@Deprecated
 	protected void finishOnUiThread() {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				finish();
diff --git a/briar-android/src/org/briarproject/android/BriarFragmentActivity.java b/briar-android/src/org/briarproject/android/BriarFragmentActivity.java
index 513ace7b56..946ebbd356 100644
--- a/briar-android/src/org/briarproject/android/BriarFragmentActivity.java
+++ b/briar-android/src/org/briarproject/android/BriarFragmentActivity.java
@@ -1,7 +1,6 @@
 package org.briarproject.android;
 
 import android.support.annotation.AnimRes;
-import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentTransaction;
 import android.support.v7.app.ActionBar;
 import android.support.v7.app.AlertDialog;
@@ -12,6 +11,8 @@ import org.briarproject.android.contact.ContactListFragment;
 import org.briarproject.android.forum.ForumListFragment;
 import org.briarproject.android.fragment.BaseFragment;
 
+import static android.support.v4.app.FragmentManager.POP_BACK_STACK_INCLUSIVE;
+
 /**
  * This class should be extended by classes that wish to utilise fragments in
  * Briar, it encapsulates all fragment related code.
@@ -33,11 +34,8 @@ public abstract class BriarFragmentActivity extends BriarActivity {
 	}
 
 	void clearBackStack() {
-		getSupportFragmentManager()
-				.popBackStackImmediate(
-						null,
-						FragmentManager.POP_BACK_STACK_INCLUSIVE
-				);
+		getSupportFragmentManager().popBackStackImmediate(null,
+				POP_BACK_STACK_INCLUSIVE);
 	}
 
 	@Override
diff --git a/briar-android/src/org/briarproject/android/DestroyableActivity.java b/briar-android/src/org/briarproject/android/DestroyableActivity.java
deleted file mode 100644
index 94622406de..0000000000
--- a/briar-android/src/org/briarproject/android/DestroyableActivity.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package org.briarproject.android;
-
-import android.support.annotation.UiThread;
-
-public interface DestroyableActivity {
-
-	void runOnUiThread(Runnable runnable);
-
-	@UiThread
-	boolean hasBeenDestroyed();
-
-}
diff --git a/briar-android/src/org/briarproject/android/DestroyableContext.java b/briar-android/src/org/briarproject/android/DestroyableContext.java
new file mode 100644
index 0000000000..75faa0d104
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/DestroyableContext.java
@@ -0,0 +1,6 @@
+package org.briarproject.android;
+
+public interface DestroyableContext {
+
+	void runOnUiThreadUnlessDestroyed(Runnable runnable);
+}
diff --git a/briar-android/src/org/briarproject/android/NavDrawerActivity.java b/briar-android/src/org/briarproject/android/NavDrawerActivity.java
index a7af5d0d06..62af704f57 100644
--- a/briar-android/src/org/briarproject/android/NavDrawerActivity.java
+++ b/briar-android/src/org/briarproject/android/NavDrawerActivity.java
@@ -27,7 +27,7 @@ import org.briarproject.android.controller.NavDrawerController;
 import org.briarproject.android.controller.TransportStateListener;
 import org.briarproject.android.controller.handler.UiResultHandler;
 import org.briarproject.android.forum.ForumListFragment;
-import org.briarproject.android.fragment.BaseFragment;
+import org.briarproject.android.fragment.BaseFragment.BaseFragmentListener;
 import org.briarproject.api.TransportId;
 import org.briarproject.api.identity.LocalAuthor;
 
@@ -43,7 +43,7 @@ import static android.support.v4.widget.DrawerLayout.LOCK_MODE_UNLOCKED;
 import static android.view.View.INVISIBLE;
 
 public class NavDrawerActivity extends BriarFragmentActivity implements
-		BaseFragment.BaseFragmentListener, TransportStateListener,
+		BaseFragmentListener, TransportStateListener,
 		OnNavigationItemSelectedListener {
 
 	static final String INTENT_CONTACTS = "intent_contacts";
@@ -58,9 +58,8 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
 	private ActionBarDrawerToggle drawerToggle;
 
 	@Inject
-	protected NavDrawerController controller;
+	NavDrawerController controller;
 
-	private Toolbar toolbar;
 	private DrawerLayout drawerLayout;
 	private TextView progressTitle;
 	private ViewGroup progressViewGroup;
@@ -78,11 +77,9 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
 //		clearBackStack();
 		if (intent.getBooleanExtra(INTENT_FORUMS, false)) {
 			startFragment(ForumListFragment.newInstance());
-		}
-		else if (intent.getBooleanExtra(INTENT_CONTACTS, false)) {
+		} else if (intent.getBooleanExtra(INTENT_CONTACTS, false)) {
 			startFragment(ContactListFragment.newInstance());
-		}
-		else if (intent.getBooleanExtra(INTENT_BLOGS, false)) {
+		} else if (intent.getBooleanExtra(INTENT_BLOGS, false)) {
 			startFragment(FeedFragment.newInstance());
 		}
 		setIntent(null);
@@ -100,7 +97,7 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
 		exitIfStartupFailed(getIntent());
 		setContentView(R.layout.activity_nav_drawer);
 
-		toolbar = (Toolbar) findViewById(R.id.toolbar);
+		Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
 		drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
 		NavigationView navigation =
 				(NavigationView) findViewById(R.id.navigation);
@@ -318,7 +315,7 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
 	}
 
 	private void setTransport(final TransportId id, final boolean enabled) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				if (transports == null || transportsAdapter == null) return;
diff --git a/briar-android/src/org/briarproject/android/blogs/BaseController.java b/briar-android/src/org/briarproject/android/blogs/BaseController.java
index bfd1a0b13a..a2f4b7d26a 100644
--- a/briar-android/src/org/briarproject/android/blogs/BaseController.java
+++ b/briar-android/src/org/briarproject/android/blogs/BaseController.java
@@ -3,6 +3,7 @@ package org.briarproject.android.blogs;
 import android.support.annotation.Nullable;
 import android.support.annotation.UiThread;
 
+import org.briarproject.android.DestroyableContext;
 import org.briarproject.android.controller.handler.ResultExceptionHandler;
 import org.briarproject.api.blogs.BlogPostHeader;
 import org.briarproject.api.db.DbException;
@@ -33,9 +34,13 @@ interface BaseController {
 
 	void setOnBlogPostAddedListener(OnBlogPostAddedListener listener);
 
-	interface OnBlogPostAddedListener {
+	interface OnBlogPostAddedListener extends DestroyableContext {
+
 		@UiThread
 		void onBlogPostAdded(BlogPostHeader header, boolean local);
+
+		@UiThread
+		void onBlogRemoved();
 	}
 
 }
diff --git a/briar-android/src/org/briarproject/android/blogs/BaseControllerImpl.java b/briar-android/src/org/briarproject/android/blogs/BaseControllerImpl.java
index 3c4f1bc21b..f624023bd3 100644
--- a/briar-android/src/org/briarproject/android/blogs/BaseControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/blogs/BaseControllerImpl.java
@@ -1,6 +1,5 @@
 package org.briarproject.android.blogs;
 
-import android.app.Activity;
 import android.support.annotation.CallSuper;
 import android.support.annotation.Nullable;
 
@@ -39,16 +38,14 @@ abstract class BaseControllerImpl extends DbControllerImpl
 			Logger.getLogger(BaseControllerImpl.class.getName());
 
 	@Inject
-	protected Activity activity;
+	EventBus eventBus;
 	@Inject
-	protected EventBus eventBus;
+	AndroidNotificationManager notificationManager;
 	@Inject
-	protected AndroidNotificationManager notificationManager;
-	@Inject
-	protected IdentityManager identityManager;
+	IdentityManager identityManager;
 
 	@Inject
-	protected volatile BlogManager blogManager;
+	volatile BlogManager blogManager;
 
 	private final Map<MessageId, String> bodyCache = new ConcurrentHashMap<>();
 	private final Map<MessageId, BlogPostHeader> headerCache =
@@ -75,12 +72,12 @@ abstract class BaseControllerImpl extends DbControllerImpl
 	@CallSuper
 	public void eventOccurred(Event e) {
 		if (e instanceof BlogPostAddedEvent) {
-			final BlogPostAddedEvent m = (BlogPostAddedEvent) e;
+			final BlogPostAddedEvent b = (BlogPostAddedEvent) e;
 			LOG.info("New blog post added");
-			activity.runOnUiThread(new Runnable() {
+			listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 				@Override
 				public void run() {
-					listener.onBlogPostAdded(m.getHeader(), m.isLocal());
+					listener.onBlogPostAdded(b.getHeader(), b.isLocal());
 				}
 			});
 		}
@@ -110,8 +107,7 @@ abstract class BaseControllerImpl extends DbControllerImpl
 		});
 	}
 
-	protected Collection<BlogPostItem> loadItems(GroupId groupId)
-			throws DbException {
+	Collection<BlogPostItem> loadItems(GroupId groupId) throws DbException {
 		long now = System.currentTimeMillis();
 		Collection<BlogPostHeader> headers =
 				blogManager.getPostHeaders(groupId);
diff --git a/briar-android/src/org/briarproject/android/blogs/BasePostFragment.java b/briar-android/src/org/briarproject/android/blogs/BasePostFragment.java
index 85c5dff335..04ee0a747d 100644
--- a/briar-android/src/org/briarproject/android/blogs/BasePostFragment.java
+++ b/briar-android/src/org/briarproject/android/blogs/BasePostFragment.java
@@ -22,7 +22,7 @@ import static org.briarproject.android.util.AndroidUtils.MIN_RESOLUTION;
 
 abstract class BasePostFragment extends BaseFragment {
 
-	private final Logger LOG =
+	private static final Logger LOG =
 			Logger.getLogger(BasePostFragment.class.getName());
 
 	private View view;
diff --git a/briar-android/src/org/briarproject/android/blogs/BasePostPagerFragment.java b/briar-android/src/org/briarproject/android/blogs/BasePostPagerFragment.java
index e27c1470f5..424fa5d45d 100644
--- a/briar-android/src/org/briarproject/android/blogs/BasePostPagerFragment.java
+++ b/briar-android/src/org/briarproject/android/blogs/BasePostPagerFragment.java
@@ -90,6 +90,7 @@ abstract class BasePostPagerFragment extends BaseFragment
 
 	abstract void loadBlogPost(BlogPostHeader header);
 
+	@UiThread
 	protected void onBlogPostsLoaded(MessageId select,
 			Collection<BlogPostItem> posts) {
 
@@ -98,6 +99,7 @@ abstract class BasePostPagerFragment extends BaseFragment
 		selectPost(select);
 	}
 
+	@UiThread
 	protected void onBlogPostsLoadedException(DbException exception) {
 		// TODO: Decide how to handle errors in the UI
 		finish();
@@ -174,4 +176,8 @@ abstract class BasePostPagerFragment extends BaseFragment
 		}
 	}
 
+	@Override
+	public void onBlogRemoved() {
+		finish();
+	}
 }
diff --git a/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java b/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java
index ebc9764689..6dd1c6ab54 100644
--- a/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java
@@ -1,5 +1,7 @@
 package org.briarproject.android.blogs;
 
+import android.app.Activity;
+
 import org.briarproject.android.controller.ActivityLifecycleController;
 import org.briarproject.android.controller.handler.ResultExceptionHandler;
 import org.briarproject.api.blogs.Blog;
@@ -32,7 +34,7 @@ public class BlogControllerImpl extends BaseControllerImpl
 	}
 
 	@Override
-	public void onActivityCreate() {
+	public void onActivityCreate(Activity activity) {
 	}
 
 	@Override
@@ -69,11 +71,10 @@ public class BlogControllerImpl extends BaseControllerImpl
 			GroupRemovedEvent s = (GroupRemovedEvent) e;
 			if (s.getGroup().getId().equals(groupId)) {
 				LOG.info("Blog removed");
-				activity.runOnUiThread(new Runnable() {
+				listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 					@Override
 					public void run() {
-						// TODO: Not the controller's job, add a listener method
-						activity.finish();
+						listener.onBlogRemoved();
 					}
 				});
 			}
diff --git a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java
index 963b7175ea..25d266c312 100644
--- a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java
+++ b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java
@@ -160,8 +160,8 @@ public class BlogFragment extends BaseFragment implements
 				getActivity().onBackPressed();
 				return true;
 			case R.id.action_write_blog_post:
-				Intent i =
-						new Intent(getActivity(), WriteBlogPostActivity.class);
+				Intent i = new Intent(getActivity(),
+						WriteBlogPostActivity.class);
 				i.putExtra(GROUP_ID, groupId.getBytes());
 				i.putExtra(BLOG_NAME, blogName);
 				startActivityForResult(i, REQUEST_WRITE_POST,
@@ -224,7 +224,7 @@ public class BlogFragment extends BaseFragment implements
 					@Override
 					public void onExceptionUi(DbException exception) {
 						// TODO: Decide how to handle errors in the UI
-						getActivity().finish();
+						finish();
 					}
 				}
 		);
@@ -338,7 +338,7 @@ public class BlogFragment extends BaseFragment implements
 						Toast.makeText(getActivity(),
 								R.string.blogs_blog_removed, LENGTH_SHORT)
 								.show();
-						getActivity().supportFinishAfterTransition();
+						finish();
 					}
 
 					@Override
@@ -349,4 +349,8 @@ public class BlogFragment extends BaseFragment implements
 				});
 	}
 
+	@Override
+	public void onBlogRemoved() {
+		finish();
+	}
 }
diff --git a/briar-android/src/org/briarproject/android/blogs/BlogPostPagerFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogPostPagerFragment.java
index 560e62e38b..3db8c4d084 100644
--- a/briar-android/src/org/briarproject/android/blogs/BlogPostPagerFragment.java
+++ b/briar-android/src/org/briarproject/android/blogs/BlogPostPagerFragment.java
@@ -41,6 +41,7 @@ public class BlogPostPagerFragment extends BasePostPagerFragment {
 	}
 
 
+	@Override
 	void loadBlogPosts(final MessageId select) {
 		blogController.loadBlogPosts(
 				new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
@@ -57,6 +58,7 @@ public class BlogPostPagerFragment extends BasePostPagerFragment {
 				});
 	}
 
+	@Override
 	void loadBlogPost(BlogPostHeader header) {
 		blogController.loadBlogPost(header,
 				new UiResultExceptionHandler<BlogPostItem, DbException>(
@@ -73,5 +75,4 @@ public class BlogPostPagerFragment extends BasePostPagerFragment {
 					}
 				});
 	}
-
 }
diff --git a/briar-android/src/org/briarproject/android/blogs/FeedFragment.java b/briar-android/src/org/briarproject/android/blogs/FeedFragment.java
index a8a8cea9d7..d07a800d59 100644
--- a/briar-android/src/org/briarproject/android/blogs/FeedFragment.java
+++ b/briar-android/src/org/briarproject/android/blogs/FeedFragment.java
@@ -231,4 +231,9 @@ public class FeedFragment extends BaseFragment implements
 		}
 		s.show();
 	}
+
+	@Override
+	public void onBlogRemoved() {
+		finish();
+	}
 }
diff --git a/briar-android/src/org/briarproject/android/blogs/FeedPostPagerFragment.java b/briar-android/src/org/briarproject/android/blogs/FeedPostPagerFragment.java
index 5f5c351dc1..b37d99eefe 100644
--- a/briar-android/src/org/briarproject/android/blogs/FeedPostPagerFragment.java
+++ b/briar-android/src/org/briarproject/android/blogs/FeedPostPagerFragment.java
@@ -74,5 +74,4 @@ public class FeedPostPagerFragment extends BasePostPagerFragment {
 					}
 				});
 	}
-
 }
diff --git a/briar-android/src/org/briarproject/android/blogs/ReblogFragment.java b/briar-android/src/org/briarproject/android/blogs/ReblogFragment.java
index d5d799692e..e3d50dfeef 100644
--- a/briar-android/src/org/briarproject/android/blogs/ReblogFragment.java
+++ b/briar-android/src/org/briarproject/android/blogs/ReblogFragment.java
@@ -65,12 +65,7 @@ public class ReblogFragment extends BaseFragment implements TextInputListener {
 	@Override
 	public void onAttach(Context context) {
 		super.onAttach(context);
-		try {
-			listener = (BaseFragmentListener) context;
-		} catch (ClassCastException e) {
-			throw new ClassCastException(
-					"Using class must implement BaseFragmentListener");
-		}
+		listener = (BaseFragmentListener) context;
 	}
 
 	@Override
@@ -93,12 +88,6 @@ public class ReblogFragment extends BaseFragment implements TextInputListener {
 		return v;
 	}
 
-	@Override
-	public void onActivityCreated(@Nullable Bundle savedInstanceState) {
-		super.onActivityCreated(savedInstanceState);
-		listener.getActivityComponent().inject(this);
-	}
-
 	@Override
 	public void onStart() {
 		super.onStart();
diff --git a/briar-android/src/org/briarproject/android/blogs/RssFeedImportActivity.java b/briar-android/src/org/briarproject/android/blogs/RssFeedImportActivity.java
index f16663a1c4..2150b31bad 100644
--- a/briar-android/src/org/briarproject/android/blogs/RssFeedImportActivity.java
+++ b/briar-android/src/org/briarproject/android/blogs/RssFeedImportActivity.java
@@ -42,10 +42,11 @@ public class RssFeedImportActivity extends BriarActivity {
 
 	@Inject
 	@IoExecutor
-	protected Executor ioExecutor;
+	Executor ioExecutor;
 
 	// Fields that are accessed from background threads must be volatile
 	private volatile GroupId groupId = null;
+
 	@Inject
 	@SuppressWarnings("WeakerAccess")
 	volatile FeedManager feedManager;
@@ -139,7 +140,7 @@ public class RssFeedImportActivity extends BriarActivity {
 	}
 
 	private void feedImported() {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				supportFinishAfterTransition();
@@ -148,11 +149,9 @@ public class RssFeedImportActivity extends BriarActivity {
 	}
 
 	private void importFailed() {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
-				if (RssFeedImportActivity.this.hasBeenDestroyed()) return;
-
 				// hide progress bar, show publish button
 				progressBar.setVisibility(GONE);
 				importButton.setVisibility(VISIBLE);
diff --git a/briar-android/src/org/briarproject/android/blogs/RssFeedManageActivity.java b/briar-android/src/org/briarproject/android/blogs/RssFeedManageActivity.java
index 60230717bb..2fe3ad30cc 100644
--- a/briar-android/src/org/briarproject/android/blogs/RssFeedManageActivity.java
+++ b/briar-android/src/org/briarproject/android/blogs/RssFeedManageActivity.java
@@ -40,6 +40,7 @@ public class RssFeedManageActivity extends BriarActivity
 
 	// Fields that are accessed from background threads must be volatile
 	private volatile GroupId groupId = null;
+
 	@Inject
 	@SuppressWarnings("WeakerAccess")
 	volatile FeedManager feedManager;
@@ -135,7 +136,7 @@ public class RssFeedManageActivity extends BriarActivity
 	}
 
 	private void addFeeds(final List<Feed> feeds) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				if (feeds.size() == 0) list.showData();
@@ -145,7 +146,7 @@ public class RssFeedManageActivity extends BriarActivity
 	}
 
 	private void onFeedDeleted(final Feed feed) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				adapter.remove(feed);
@@ -154,7 +155,7 @@ public class RssFeedManageActivity extends BriarActivity
 	}
 
 	private void onDeleteError() {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				Snackbar.make(list,
diff --git a/briar-android/src/org/briarproject/android/blogs/WriteBlogPostActivity.java b/briar-android/src/org/briarproject/android/blogs/WriteBlogPostActivity.java
index d657fe913b..70d326ca42 100644
--- a/briar-android/src/org/briarproject/android/blogs/WriteBlogPostActivity.java
+++ b/briar-android/src/org/briarproject/android/blogs/WriteBlogPostActivity.java
@@ -44,7 +44,7 @@ public class WriteBlogPostActivity extends BriarActivity
 			Logger.getLogger(WriteBlogPostActivity.class.getName());
 
 	@Inject
-	protected AndroidNotificationManager notificationManager;
+	AndroidNotificationManager notificationManager;
 
 	private TextInputView input;
 	private ProgressBar progressBar;
@@ -52,7 +52,7 @@ public class WriteBlogPostActivity extends BriarActivity
 	// Fields that are accessed from background threads must be volatile
 	private volatile GroupId groupId;
 	@Inject
-	protected volatile IdentityManager identityManager;
+	volatile IdentityManager identityManager;
 	@Inject
 	volatile BlogPostFactory blogPostFactory;
 	@Inject
@@ -168,7 +168,7 @@ public class WriteBlogPostActivity extends BriarActivity
 	}
 
 	private void postPublished() {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				setResult(RESULT_OK);
@@ -178,7 +178,7 @@ public class WriteBlogPostActivity extends BriarActivity
 	}
 
 	private void postFailedToPublish() {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				// hide progress bar, show publish button
diff --git a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
index 22f77a841d..c4536bd9cb 100644
--- a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
+++ b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
@@ -63,33 +63,29 @@ import static org.briarproject.android.BriarActivity.GROUP_ID;
 
 public class ContactListFragment extends BaseFragment implements EventListener {
 
-	public final static String TAG = "ContactListFragment";
-
-	private static final Logger LOG =
-			Logger.getLogger(ContactListFragment.class.getName());
+	public static final String TAG = ContactListFragment.class.getName();
+	private static final Logger LOG = Logger.getLogger(TAG);
 
 	@Inject
 	ConnectionRegistry connectionRegistry;
 	@Inject
-	protected EventBus eventBus;
+	EventBus eventBus;
 	@Inject
-	protected AndroidNotificationManager notificationManager;
+	AndroidNotificationManager notificationManager;
 
-	private ContactListAdapter adapter = null;
-	private BriarRecyclerView list = null;
+	private ContactListAdapter adapter;
+	private BriarRecyclerView list;
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject
-	protected volatile ContactManager contactManager;
+	volatile ContactManager contactManager;
 	@Inject
-	protected volatile IdentityManager identityManager;
+	volatile IdentityManager identityManager;
 	@Inject
-	protected volatile ConversationManager conversationManager;
+	volatile ConversationManager conversationManager;
 
 	public static ContactListFragment newInstance() {
-
 		Bundle args = new Bundle();
-
 		ContactListFragment fragment = new ContactListFragment();
 		fragment.setArguments(args);
 		return fragment;
@@ -230,7 +226,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
 	}
 
 	private void displayContacts(final List<ContactListItem> contacts) {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				if (contacts.size() == 0) list.showData();
@@ -284,7 +280,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
 	}
 
 	private void updateItem(final ContactId c, final ConversationItem m) {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				int position = adapter.findItemPosition(c);
@@ -298,7 +294,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
 	}
 
 	private void updateItem(final GroupId g, final ConversationItem m) {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				int position = adapter.findItemPosition(g);
@@ -312,7 +308,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
 	}
 
 	private void removeItem(final ContactId c) {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				int position = adapter.findItemPosition(c);
@@ -323,7 +319,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
 	}
 
 	private void setConnected(final ContactId c, final boolean connected) {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				int position = adapter.findItemPosition(c);
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
index 75c0b88c8f..1d563ad0ce 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
@@ -130,21 +130,21 @@ public class ConversationActivity extends BriarActivity
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject
-	protected volatile ContactManager contactManager;
+	volatile ContactManager contactManager;
 	@Inject
-	protected volatile MessagingManager messagingManager;
+	volatile MessagingManager messagingManager;
 	@Inject
-	protected volatile EventBus eventBus;
+	volatile EventBus eventBus;
 	@Inject
-	protected volatile SettingsManager settingsManager;
+	volatile SettingsManager settingsManager;
 	@Inject
 	volatile PrivateMessageFactory privateMessageFactory;
 	@Inject
-	protected volatile IntroductionManager introductionManager;
+	volatile IntroductionManager introductionManager;
 	@Inject
-	protected volatile ForumSharingManager forumSharingManager;
+	volatile ForumSharingManager forumSharingManager;
 	@Inject
-	protected volatile BlogSharingManager blogSharingManager;
+	volatile BlogSharingManager blogSharingManager;
 
 	private volatile GroupId groupId = null;
 	private volatile ContactId contactId = null;
@@ -309,7 +309,7 @@ public class ConversationActivity extends BriarActivity
 	}
 
 	private void displayContactDetails() {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				toolbarAvatar.setImageDrawable(
@@ -374,7 +374,7 @@ public class ConversationActivity extends BriarActivity
 	private void displayMessages(final Collection<PrivateMessageHeader> headers,
 			final Collection<IntroductionMessage> introductions,
 			final Collection<InvitationMessage> invitations) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				textInputView.setSendButtonEnabled(true);
@@ -446,7 +446,7 @@ public class ConversationActivity extends BriarActivity
 	}
 
 	private void displayMessageBody(final MessageId m, final byte[] body) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				bodyCache.put(m, body);
@@ -466,7 +466,7 @@ public class ConversationActivity extends BriarActivity
 	}
 
 	private void addConversationItem(final ConversationItem item) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				adapter.add(item);
@@ -599,7 +599,7 @@ public class ConversationActivity extends BriarActivity
 	}
 
 	private void markMessageReadIfNew(final BaseMessageHeader h) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				ConversationItem item = adapter.getLastItem();
@@ -635,7 +635,7 @@ public class ConversationActivity extends BriarActivity
 
 	private void markMessages(final Collection<MessageId> messageIds,
 			final boolean sent, final boolean seen) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				Set<MessageId> messages = new HashSet<>(messageIds);
@@ -747,7 +747,7 @@ public class ConversationActivity extends BriarActivity
 	}
 
 	private void finishAfterContactRemoved() {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				String deleted = getString(R.string.contact_deleted_toast);
@@ -781,7 +781,7 @@ public class ConversationActivity extends BriarActivity
 	}
 
 	private void enableIntroductionAction(final MenuItem item) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				item.setEnabled(true);
@@ -790,7 +790,7 @@ public class ConversationActivity extends BriarActivity
 	}
 
 	private void showIntroductionOnboarding() {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				// find view of overflow icon
@@ -877,7 +877,7 @@ public class ConversationActivity extends BriarActivity
 	}
 
 	private void introductionResponseError() {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				Toast.makeText(ConversationActivity.this,
diff --git a/briar-android/src/org/briarproject/android/controller/ActivityLifecycleController.java b/briar-android/src/org/briarproject/android/controller/ActivityLifecycleController.java
index 68b15592ce..303f9b89b4 100644
--- a/briar-android/src/org/briarproject/android/controller/ActivityLifecycleController.java
+++ b/briar-android/src/org/briarproject/android/controller/ActivityLifecycleController.java
@@ -1,7 +1,10 @@
 package org.briarproject.android.controller;
 
+import android.app.Activity;
+
 public interface ActivityLifecycleController {
-	void onActivityCreate();
+
+	void onActivityCreate(Activity activity);
 
 	void onActivityResume();
 
diff --git a/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java b/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java
index 7dd180a448..459730ebd2 100644
--- a/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java
@@ -20,11 +20,11 @@ public class BriarControllerImpl implements BriarController {
 			Logger.getLogger(BriarControllerImpl.class.getName());
 
 	@Inject
-	protected BriarServiceConnection serviceConnection;
+	BriarServiceConnection serviceConnection;
 	@Inject
-	protected DatabaseConfig databaseConfig;
+	DatabaseConfig databaseConfig;
 	@Inject
-	protected Activity activity;
+	Activity activity;
 
 	private boolean bound = false;
 
@@ -35,7 +35,7 @@ public class BriarControllerImpl implements BriarController {
 
 	@Override
 	@CallSuper
-	public void onActivityCreate() {
+	public void onActivityCreate(Activity activity) {
 		if (databaseConfig.getEncryptionKey() != null) startAndBindService();
 	}
 
@@ -90,7 +90,7 @@ public class BriarControllerImpl implements BriarController {
 		}.start();
 	}
 
-	protected void unbindService() {
+	private void unbindService() {
 		if (bound) activity.unbindService(serviceConnection);
 	}
 
diff --git a/briar-android/src/org/briarproject/android/controller/NavDrawerController.java b/briar-android/src/org/briarproject/android/controller/NavDrawerController.java
index 8cd8aa8606..8d25d45b30 100644
--- a/briar-android/src/org/briarproject/android/controller/NavDrawerController.java
+++ b/briar-android/src/org/briarproject/android/controller/NavDrawerController.java
@@ -6,8 +6,6 @@ import org.briarproject.api.identity.LocalAuthor;
 
 public interface NavDrawerController extends ActivityLifecycleController {
 
-	void setTransportListener(TransportStateListener transportListener);
-
 	boolean isTransportRunning(TransportId transportId);
 
 	void storeLocalAuthor(LocalAuthor author,
diff --git a/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImpl.java b/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImpl.java
index 23a680bd39..3cfa06d772 100644
--- a/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImpl.java
@@ -30,19 +30,17 @@ public class NavDrawerControllerImpl extends DbControllerImpl
 			Logger.getLogger(NavDrawerControllerImpl.class.getName());
 
 	@Inject
-	protected ReferenceManager referenceManager;
+	ReferenceManager referenceManager;
 	@Inject
-	protected PluginManager pluginManager;
+	PluginManager pluginManager;
 	@Inject
-	protected EventBus eventBus;
-	@Inject
-	protected Activity activity;
+	EventBus eventBus;
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject
 	protected volatile IdentityManager identityManager;
 
-	private TransportStateListener transportStateListener;
+	private TransportStateListener listener;
 
 	@Inject
 	public NavDrawerControllerImpl() {
@@ -50,8 +48,8 @@ public class NavDrawerControllerImpl extends DbControllerImpl
 	}
 
 	@Override
-	public void onActivityCreate() {
-
+	public void onActivityCreate(Activity activity) {
+		listener = (TransportStateListener) activity;
 	}
 
 	@Override
@@ -88,21 +86,14 @@ public class NavDrawerControllerImpl extends DbControllerImpl
 
 	private void transportStateUpdate(final TransportId id,
 			final boolean enabled) {
-		activity.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
-				if (transportStateListener != null) {
-					transportStateListener.stateUpdate(id, enabled);
-				}
+				listener.stateUpdate(id, enabled);
 			}
 		});
 	}
 
-	@Override
-	public void setTransportListener(TransportStateListener transportListener) {
-		this.transportStateListener = transportListener;
-	}
-
 	@Override
 	public boolean isTransportRunning(TransportId transportId) {
 		Plugin plugin = pluginManager.getPlugin(transportId);
diff --git a/briar-android/src/org/briarproject/android/controller/TransportStateListener.java b/briar-android/src/org/briarproject/android/controller/TransportStateListener.java
index 7f472b6017..3bb1c0a883 100644
--- a/briar-android/src/org/briarproject/android/controller/TransportStateListener.java
+++ b/briar-android/src/org/briarproject/android/controller/TransportStateListener.java
@@ -1,8 +1,9 @@
 package org.briarproject.android.controller;
 
+import org.briarproject.android.DestroyableContext;
 import org.briarproject.api.TransportId;
 
-public interface TransportStateListener {
+public interface TransportStateListener extends DestroyableContext {
 
 	void stateUpdate(TransportId id, boolean enabled);
 }
diff --git a/briar-android/src/org/briarproject/android/controller/handler/UiResultExceptionHandler.java b/briar-android/src/org/briarproject/android/controller/handler/UiResultExceptionHandler.java
index 04ea2ebad2..b2d01d4f74 100644
--- a/briar-android/src/org/briarproject/android/controller/handler/UiResultExceptionHandler.java
+++ b/briar-android/src/org/briarproject/android/controller/handler/UiResultExceptionHandler.java
@@ -2,35 +2,33 @@ package org.briarproject.android.controller.handler;
 
 import android.support.annotation.UiThread;
 
-import org.briarproject.android.DestroyableActivity;
+import org.briarproject.android.DestroyableContext;
 
 public abstract class UiResultExceptionHandler<R, E extends Exception>
 		implements ResultExceptionHandler<R, E> {
 
-	private final DestroyableActivity listener;
+	private final DestroyableContext listener;
 
-	protected UiResultExceptionHandler(DestroyableActivity listener) {
+	protected UiResultExceptionHandler(DestroyableContext listener) {
 		this.listener = listener;
 	}
 
 	@Override
 	public void onResult(final R result) {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
-				if (!listener.hasBeenDestroyed())
-					onResultUi(result);
+				onResultUi(result);
 			}
 		});
 	}
 
 	@Override
 	public void onException(final E exception) {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
-				if (!listener.hasBeenDestroyed())
-					onExceptionUi(exception);
+				onExceptionUi(exception);
 			}
 		});
 	}
diff --git a/briar-android/src/org/briarproject/android/controller/handler/UiResultHandler.java b/briar-android/src/org/briarproject/android/controller/handler/UiResultHandler.java
index 9c2fbe6142..6516ff7151 100644
--- a/briar-android/src/org/briarproject/android/controller/handler/UiResultHandler.java
+++ b/briar-android/src/org/briarproject/android/controller/handler/UiResultHandler.java
@@ -2,24 +2,22 @@ package org.briarproject.android.controller.handler;
 
 import android.support.annotation.UiThread;
 
-import org.briarproject.android.DestroyableActivity;
-import org.briarproject.android.fragment.BaseFragment.BaseFragmentListener;
+import org.briarproject.android.DestroyableContext;
 
 public abstract class UiResultHandler<R> implements ResultHandler<R> {
 
-	private final DestroyableActivity listener;
+	private final DestroyableContext listener;
 
-	protected UiResultHandler(DestroyableActivity listener) {
+	protected UiResultHandler(DestroyableContext listener) {
 		this.listener = listener;
 	}
 
 	@Override
 	public void onResult(final R result) {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
-				if (!listener.hasBeenDestroyed())
-					onResultUi(result);
+				onResultUi(result);
 			}
 		});
 	}
diff --git a/briar-android/src/org/briarproject/android/forum/CreateForumActivity.java b/briar-android/src/org/briarproject/android/forum/CreateForumActivity.java
index f1de11e32b..ff1644b1c9 100644
--- a/briar-android/src/org/briarproject/android/forum/CreateForumActivity.java
+++ b/briar-android/src/org/briarproject/android/forum/CreateForumActivity.java
@@ -144,7 +144,7 @@ public class CreateForumActivity extends BriarActivity
 	}
 
 	private void displayForum(final Forum f) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				Intent i = new Intent(CreateForumActivity.this,
diff --git a/briar-android/src/org/briarproject/android/forum/ForumActivity.java b/briar-android/src/org/briarproject/android/forum/ForumActivity.java
index 5660bcd23b..b7f6fe279f 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumActivity.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumActivity.java
@@ -267,9 +267,8 @@ public class ForumActivity extends BriarActivity implements
 			// root post
 			forumController.createPost(StringUtils.toUtf8(text), resultHandler);
 		} else {
-			forumController
-					.createPost(StringUtils.toUtf8(text), replyEntry.getId(),
-							resultHandler);
+			forumController.createPost(StringUtils.toUtf8(text),
+					replyEntry.getId(), resultHandler);
 		}
 		textInput.hideSoftKeyboard();
 		textInput.setVisibility(GONE);
@@ -344,7 +343,7 @@ public class ForumActivity extends BriarActivity implements
 	}
 
 	@Override
-	public void onExternalEntryAdded(ForumPostHeader header) {
+	public void onForumPostReceived(ForumPostHeader header) {
 		forumController.loadPost(header,
 				new UiResultExceptionHandler<ForumEntry, DbException>(this) {
 					@Override
@@ -357,6 +356,10 @@ public class ForumActivity extends BriarActivity implements
 						// TODO add proper exception handling
 					}
 				});
+	}
 
+	@Override
+	public void onForumRemoved() {
+		finish();
 	}
 }
diff --git a/briar-android/src/org/briarproject/android/forum/ForumController.java b/briar-android/src/org/briarproject/android/forum/ForumController.java
index 459aafb2ff..ad08dbc4dd 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumController.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumController.java
@@ -3,6 +3,7 @@ package org.briarproject.android.forum;
 import android.support.annotation.Nullable;
 import android.support.annotation.UiThread;
 
+import org.briarproject.android.DestroyableContext;
 import org.briarproject.android.controller.ActivityLifecycleController;
 import org.briarproject.android.controller.handler.ResultExceptionHandler;
 import org.briarproject.android.controller.handler.ResultHandler;
@@ -38,9 +39,13 @@ public interface ForumController extends ActivityLifecycleController {
 	void createPost(byte[] body, MessageId parentId,
 			ResultExceptionHandler<ForumEntry, DbException> resultHandler);
 
-	interface ForumPostListener {
+	interface ForumPostListener extends DestroyableContext {
+
+		@UiThread
+		void onForumPostReceived(ForumPostHeader header);
+
 		@UiThread
-		void onExternalEntryAdded(ForumPostHeader header);
+		void onForumRemoved();
 	}
 
 }
diff --git a/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java b/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java
index 98f7ac139e..0a1cb23a39 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java
@@ -51,21 +51,19 @@ public class ForumControllerImpl extends DbControllerImpl
 	private static final Logger LOG =
 			Logger.getLogger(ForumControllerImpl.class.getName());
 
-	@Inject
-	protected Activity activity;
 	@Inject
 	@CryptoExecutor
-	protected Executor cryptoExecutor;
+	Executor cryptoExecutor;
 	@Inject
 	volatile ForumPostFactory forumPostFactory;
 	@Inject
-	protected volatile CryptoComponent crypto;
+	volatile CryptoComponent crypto;
 	@Inject
-	protected volatile ForumManager forumManager;
+	volatile ForumManager forumManager;
 	@Inject
-	protected volatile EventBus eventBus;
+	volatile EventBus eventBus;
 	@Inject
-	protected volatile IdentityManager identityManager;
+	volatile IdentityManager identityManager;
 
 	private final Map<MessageId, byte[]> bodyCache = new ConcurrentHashMap<>();
 	private final AtomicLong newestTimeStamp = new AtomicLong();
@@ -81,7 +79,7 @@ public class ForumControllerImpl extends DbControllerImpl
 	}
 
 	@Override
-	public void onActivityCreate() {
+	public void onActivityCreate(Activity activity) {
 		if (activity instanceof ForumPostListener) {
 			listener = (ForumPostListener) activity;
 		} else {
@@ -114,10 +112,10 @@ public class ForumControllerImpl extends DbControllerImpl
 				LOG.info("Forum post received, adding...");
 				final ForumPostHeader fph = pe.getForumPostHeader();
 				updateNewestTimestamp(fph.getTimestamp());
-				activity.runOnUiThread(new Runnable() {
+				listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 					@Override
 					public void run() {
-						listener.onExternalEntryAdded(fph);
+						listener.onForumPostReceived(fph);
 					}
 				});
 			}
@@ -125,10 +123,10 @@ public class ForumControllerImpl extends DbControllerImpl
 			GroupRemovedEvent s = (GroupRemovedEvent) e;
 			if (s.getGroup().getId().equals(forum.getId())) {
 				LOG.info("Forum removed");
-				activity.runOnUiThread(new Runnable() {
+				listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 					@Override
 					public void run() {
-						activity.finish();
+						listener.onForumRemoved();
 					}
 				});
 			}
diff --git a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
index 70d82d05d9..1ebba8c1c3 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
@@ -56,13 +56,13 @@ public class ForumListFragment extends BaseEventFragment implements
 	private Snackbar snackbar;
 
 	@Inject
-	protected AndroidNotificationManager notificationManager;
+	AndroidNotificationManager notificationManager;
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject
-	protected volatile ForumManager forumManager;
+	volatile ForumManager forumManager;
 	@Inject
-	protected volatile ForumSharingManager forumSharingManager;
+	volatile ForumSharingManager forumSharingManager;
 
 	public static ForumListFragment newInstance() {
 
@@ -181,7 +181,7 @@ public class ForumListFragment extends BaseEventFragment implements
 	}
 
 	private void displayForums(final Collection<ForumListItem> forums) {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				if (forums.size() > 0) adapter.addAll(forums);
@@ -211,10 +211,9 @@ public class ForumListFragment extends BaseEventFragment implements
 	}
 
 	private void displayAvailableForums(final int availableCount) {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
-				if (getActivity() == null) return;
 				if (availableCount == 0) {
 					snackbar.dismiss();
 				} else {
@@ -245,16 +244,16 @@ public class ForumListFragment extends BaseEventFragment implements
 				removeForum(g.getGroup().getId());
 			}
 		} else if (e instanceof ForumPostReceivedEvent) {
-			ForumPostReceivedEvent m = (ForumPostReceivedEvent) e;
+			ForumPostReceivedEvent f = (ForumPostReceivedEvent) e;
 			LOG.info("Forum post added, updating...");
-			updateItem(m.getGroupId(), m.getForumPostHeader());
+			updateItem(f.getGroupId(), f.getForumPostHeader());
 		} else if (e instanceof ForumInvitationReceivedEvent) {
 			loadAvailableForums();
 		}
 	}
 
 	private void updateItem(final GroupId g, final ForumPostHeader m) {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				int position = adapter.findItemPosition(g);
@@ -268,7 +267,7 @@ public class ForumListFragment extends BaseEventFragment implements
 	}
 
 	private void removeForum(final GroupId g) {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				int position = adapter.findItemPosition(g);
diff --git a/briar-android/src/org/briarproject/android/fragment/BaseFragment.java b/briar-android/src/org/briarproject/android/fragment/BaseFragment.java
index 7c1e072acc..d671bf245c 100644
--- a/briar-android/src/org/briarproject/android/fragment/BaseFragment.java
+++ b/briar-android/src/org/briarproject/android/fragment/BaseFragment.java
@@ -7,9 +7,10 @@ import android.support.annotation.UiThread;
 import android.support.v4.app.Fragment;
 
 import org.briarproject.android.ActivityComponent;
-import org.briarproject.android.DestroyableActivity;
+import org.briarproject.android.DestroyableContext;
 
-public abstract class BaseFragment extends Fragment {
+public abstract class BaseFragment extends Fragment
+		implements DestroyableContext {
 
 	protected BaseFragmentListener listener;
 
@@ -20,12 +21,7 @@ public abstract class BaseFragment extends Fragment {
 	@Override
 	public void onAttach(Context context) {
 		super.onAttach(context);
-		try {
-			listener = (BaseFragmentListener) context;
-		} catch (ClassCastException e) {
-			throw new ClassCastException(
-					"Using class must implement BaseFragmentListener");
-		}
+		listener = (BaseFragmentListener) context;
 	}
 
 	@Override
@@ -37,7 +33,7 @@ public abstract class BaseFragment extends Fragment {
 	@Override
 	public void onActivityCreated(@Nullable Bundle savedInstanceState) {
 		super.onActivityCreated(savedInstanceState);
-		this.injectFragment(listener.getActivityComponent());
+		injectFragment(listener.getActivityComponent());
 		listener.onFragmentCreated(getUniqueTag());
 	}
 
@@ -46,7 +42,7 @@ public abstract class BaseFragment extends Fragment {
 		getActivity().supportFinishAfterTransition();
 	}
 
-	public interface BaseFragmentListener extends DestroyableActivity {
+	public interface BaseFragmentListener extends DestroyableContext {
 
 		void runOnDbThread(Runnable runnable);
 
@@ -56,4 +52,9 @@ public abstract class BaseFragment extends Fragment {
 		@UiThread
 		void onFragmentCreated(String tag);
 	}
+
+	@Override
+	public void runOnUiThreadUnlessDestroyed(Runnable r) {
+		listener.runOnUiThreadUnlessDestroyed(r);
+	}
 }
diff --git a/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java b/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java
index 5b768aaa1a..15c718b670 100644
--- a/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java
+++ b/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java
@@ -75,15 +75,10 @@ public class SettingsFragment extends PreferenceFragmentCompat
 	public void onAttach(Context context) {
 		super.onAttach(context);
 
-		try {
-			listener = (SettingsActivity) context;
-			androidExecutor = listener.getAndroidExecutor();
-			settingsManager = listener.getSettingsManager();
-			eventBus = listener.getEventBus();
-		} catch (ClassCastException e) {
-			throw new ClassCastException(context.toString()
-					+ " is not a SettingsActivity");
-		}
+		listener = (SettingsActivity) context;
+		androidExecutor = listener.getAndroidExecutor();
+		settingsManager = listener.getSettingsManager();
+		eventBus = listener.getEventBus();
 	}
 
 	@Override
@@ -195,7 +190,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
 	}
 
 	private void displaySettings() {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				enableBluetooth.setValue(Boolean.toString(bluetoothSetting));
diff --git a/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java b/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java
index 0a7ffe7bd2..6a01c3020a 100644
--- a/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java
+++ b/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java
@@ -39,10 +39,8 @@ import static java.util.logging.Level.WARNING;
 
 public class ContactChooserFragment extends BaseFragment {
 
-	public final static String TAG = "ContactChooserFragment";
-
-	private static final Logger LOG =
-			Logger.getLogger(ContactChooserFragment.class.getName());
+	public static final String TAG = ContactChooserFragment.class.getName();
+	private static final Logger LOG = Logger.getLogger(TAG);
 
 	private IntroductionActivity introductionActivity;
 	private BriarRecyclerView list;
@@ -72,12 +70,7 @@ public class ContactChooserFragment extends BaseFragment {
 	@Override
 	public void onAttach(Context context) {
 		super.onAttach(context);
-		try {
-			introductionActivity = (IntroductionActivity) context;
-		} catch (ClassCastException e) {
-			throw new InstantiationError(
-					"This fragment is only meant to be attached to the IntroductionActivity");
-		}
+		introductionActivity = (IntroductionActivity) context;
 	}
 
 	@Override
@@ -182,7 +175,7 @@ public class ContactChooserFragment extends BaseFragment {
 
 	private void displayContacts(final AuthorId localAuthorId,
 			final List<ContactListItem> contacts) {
-		introductionActivity.runOnUiThread(new Runnable() {
+		introductionActivity.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				adapter.setLocalAuthor(localAuthorId);
diff --git a/briar-android/src/org/briarproject/android/introduction/IntroductionMessageFragment.java b/briar-android/src/org/briarproject/android/introduction/IntroductionMessageFragment.java
index 05996d5dac..4b5b3c3cd0 100644
--- a/briar-android/src/org/briarproject/android/introduction/IntroductionMessageFragment.java
+++ b/briar-android/src/org/briarproject/android/introduction/IntroductionMessageFragment.java
@@ -37,12 +37,12 @@ import static java.util.logging.Level.WARNING;
 public class IntroductionMessageFragment extends BaseFragment
 		implements TextInputView.TextInputListener {
 
-	public final static String TAG = "IntroductionMessageFragment";
+	public static final String TAG =
+			IntroductionMessageFragment.class.getName();
+	private static final Logger LOG = Logger.getLogger(TAG);
 
 	private final static String CONTACT_ID_1 = "contact1";
 	private final static String CONTACT_ID_2 = "contact2";
-	private static final Logger LOG =
-			Logger.getLogger(IntroductionMessageFragment.class.getName());
 
 	private IntroductionActivity introductionActivity;
 	private ViewHolder ui;
@@ -72,12 +72,7 @@ public class IntroductionMessageFragment extends BaseFragment
 	@Override
 	public void onAttach(Context context) {
 		super.onAttach(context);
-		try {
-			introductionActivity = (IntroductionActivity) context;
-		} catch (ClassCastException e) {
-			throw new java.lang.InstantiationError(
-					"This fragment is only meant to be attached to the IntroductionActivity");
-		}
+		introductionActivity = (IntroductionActivity) context;
 	}
 
 	@Override
@@ -142,7 +137,7 @@ public class IntroductionMessageFragment extends BaseFragment
 	}
 
 	private void setUpViews(final Contact c1, final Contact c2) {
-		introductionActivity.runOnUiThread(new Runnable() {
+		introductionActivity.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				contact1 = c1;
@@ -209,7 +204,7 @@ public class IntroductionMessageFragment extends BaseFragment
 	}
 
 	private void introductionError() {
-		introductionActivity.runOnUiThread(new Runnable() {
+		introductionActivity.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				Toast.makeText(introductionActivity,
diff --git a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
index 55bdf8fd9d..bec5b346f6 100644
--- a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
+++ b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
@@ -205,6 +205,7 @@ public class AddContactActivity extends BriarActivity
 
 	void loadLocalAuthor() {
 		runOnDbThread(new Runnable() {
+			@Override
 			public void run() {
 				try {
 					long now = System.currentTimeMillis();
@@ -222,7 +223,7 @@ public class AddContactActivity extends BriarActivity
 	}
 
 	void setLocalAuthorId(final AuthorId localAuthorId) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				AddContactActivity.this.localAuthorId = localAuthorId;
@@ -283,8 +284,10 @@ public class AddContactActivity extends BriarActivity
 		}
 	}
 
+	@Override
 	public void connectionSucceeded() {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
+			@Override
 			public void run() {
 				connected = true;
 				setView(new ConfirmationCodeView(AddContactActivity.this,
@@ -293,8 +296,10 @@ public class AddContactActivity extends BriarActivity
 		});
 	}
 
+	@Override
 	public void connectionFailed() {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
+			@Override
 			public void run() {
 				connectionFailed = true;
 				setView(new ErrorView(AddContactActivity.this,
@@ -304,9 +309,11 @@ public class AddContactActivity extends BriarActivity
 		});
 	}
 
+	@Override
 	public void keyAgreementSucceeded(final int localCode,
 			final int remoteCode) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
+			@Override
 			public void run() {
 				localConfirmationCode = localCode;
 				remoteConfirmationCode = remoteCode;
@@ -315,8 +322,10 @@ public class AddContactActivity extends BriarActivity
 		});
 	}
 
+	@Override
 	public void keyAgreementFailed() {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
+			@Override
 			public void run() {
 				connectionFailed = true;
 				setView(new ErrorView(AddContactActivity.this,
@@ -326,8 +335,10 @@ public class AddContactActivity extends BriarActivity
 		});
 	}
 
+	@Override
 	public void remoteConfirmationSucceeded() {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
+			@Override
 			public void run() {
 				remoteCompared = true;
 				remoteMatched = true;
@@ -339,8 +350,10 @@ public class AddContactActivity extends BriarActivity
 		});
 	}
 
+	@Override
 	public void remoteConfirmationFailed() {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
+			@Override
 			public void run() {
 				remoteCompared = true;
 				remoteMatched = false;
@@ -352,8 +365,10 @@ public class AddContactActivity extends BriarActivity
 		});
 	}
 
+	@Override
 	public void pseudonymExchangeSucceeded(final String remoteName) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
+			@Override
 			public void run() {
 				contactName = remoteName;
 				showToastAndFinish();
@@ -361,8 +376,10 @@ public class AddContactActivity extends BriarActivity
 		});
 	}
 
+	@Override
 	public void pseudonymExchangeFailed() {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
+			@Override
 			public void run() {
 				setView(new ErrorView(AddContactActivity.this,
 						R.string.connection_failed,
@@ -386,34 +403,42 @@ public class AddContactActivity extends BriarActivity
 			this.handle = handle;
 		}
 
+		@Override
 		public void connectionSucceeded() {
 			// Wait for key agreement to succeed or fail
 		}
 
+		@Override
 		public void connectionFailed() {
 			referenceManager.removeReference(handle, InvitationTask.class);
 		}
 
+		@Override
 		public void keyAgreementSucceeded(int localCode, int remoteCode) {
 			// Wait for remote confirmation to succeed or fail
 		}
 
+		@Override
 		public void keyAgreementFailed() {
 			referenceManager.removeReference(handle, InvitationTask.class);
 		}
 
+		@Override
 		public void remoteConfirmationSucceeded() {
 			// Wait for the pseudonym exchange to succeed or fail
 		}
 
+		@Override
 		public void remoteConfirmationFailed() {
 			referenceManager.removeReference(handle, InvitationTask.class);
 		}
 
+		@Override
 		public void pseudonymExchangeSucceeded(String remoteName) {
 			referenceManager.removeReference(handle, InvitationTask.class);
 		}
 
+		@Override
 		public void pseudonymExchangeFailed() {
 			referenceManager.removeReference(handle, InvitationTask.class);
 		}
diff --git a/briar-android/src/org/briarproject/android/keyagreement/IntroFragment.java b/briar-android/src/org/briarproject/android/keyagreement/IntroFragment.java
index 2a1c2365ed..6ce313f372 100644
--- a/briar-android/src/org/briarproject/android/keyagreement/IntroFragment.java
+++ b/briar-android/src/org/briarproject/android/keyagreement/IntroFragment.java
@@ -43,12 +43,7 @@ public class IntroFragment extends BaseFragment {
 	@Override
 	public void onAttach(Context context) {
 		super.onAttach(context);
-		try {
-			screenSeenListener = (IntroScreenSeenListener) context;
-		} catch (ClassCastException e) {
-			throw new ClassCastException(
-					"Using class must implement IntroScreenSeenListener");
-		}
+		screenSeenListener = (IntroScreenSeenListener) context;
 	}
 
 	@Override
diff --git a/briar-android/src/org/briarproject/android/keyagreement/KeyAgreementActivity.java b/briar-android/src/org/briarproject/android/keyagreement/KeyAgreementActivity.java
index a9c7fb4b6b..8ef2764cf4 100644
--- a/briar-android/src/org/briarproject/android/keyagreement/KeyAgreementActivity.java
+++ b/briar-android/src/org/briarproject/android/keyagreement/KeyAgreementActivity.java
@@ -128,7 +128,7 @@ public class KeyAgreementActivity extends BriarFragmentActivity implements
 	}
 
 	private void keyAgreementFinished(final KeyAgreementResult result) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				startContactExchange(result);
@@ -162,7 +162,7 @@ public class KeyAgreementActivity extends BriarFragmentActivity implements
 
 	@Override
 	public void contactExchangeSucceeded(final Author remoteAuthor) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				String contactName = remoteAuthor.getName();
@@ -177,7 +177,7 @@ public class KeyAgreementActivity extends BriarFragmentActivity implements
 
 	@Override
 	public void duplicateContact(final Author remoteAuthor) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				String contactName = remoteAuthor.getName();
@@ -192,7 +192,7 @@ public class KeyAgreementActivity extends BriarFragmentActivity implements
 
 	@Override
 	public void contactExchangeFailed() {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				Toast.makeText(KeyAgreementActivity.this,
diff --git a/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java b/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java
index 3ebe742ebc..cef537288c 100644
--- a/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java
+++ b/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java
@@ -18,7 +18,6 @@ import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.AlphaAnimation;
 import android.widget.ImageView;
-import android.widget.ProgressBar;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -67,23 +66,21 @@ public class ShowQrCodeFragment extends BaseEventFragment
 	private static final Logger LOG = Logger.getLogger(TAG);
 
 	@Inject
-	protected KeyAgreementTaskFactory keyAgreementTaskFactory;
+	KeyAgreementTaskFactory keyAgreementTaskFactory;
 	@Inject
-	protected PayloadEncoder payloadEncoder;
+	PayloadEncoder payloadEncoder;
 	@Inject
-	protected PayloadParser payloadParser;
+	PayloadParser payloadParser;
 	@Inject
-	protected AndroidExecutor androidExecutor;
+	AndroidExecutor androidExecutor;
 	@Inject
 	@IoExecutor
-	protected Executor ioExecutor;
+	Executor ioExecutor;
 
 	private CameraView cameraView;
-	private ViewGroup cameraOverlay;
 	private View statusView;
 	private TextView status;
 	private ImageView qrCode;
-	private ProgressBar mainProgressBar;
 	private TextView mainProgressTitle;
 	private ViewGroup mainProgressContainer;
 
@@ -124,11 +121,9 @@ public class ShowQrCodeFragment extends BaseEventFragment
 		super.onViewCreated(view, savedInstanceState);
 
 		cameraView = (CameraView) view.findViewById(R.id.camera_view);
-		cameraOverlay = (ViewGroup) view.findViewById(R.id.camera_overlay);
 		statusView = view.findViewById(R.id.status_container);
 		status = (TextView) view.findViewById(R.id.connect_status);
 		qrCode = (ImageView) view.findViewById(R.id.qr_code);
-		mainProgressBar = (ProgressBar) view.findViewById(R.id.progress_bar);
 		mainProgressTitle =
 				(TextView) view.findViewById(R.id.title_progress_bar);
 		mainProgressContainer =
@@ -286,11 +281,12 @@ public class ShowQrCodeFragment extends BaseEventFragment
 			KeyAgreementAbortedEvent event = (KeyAgreementAbortedEvent) e;
 			keyAgreementAborted(event.didRemoteAbort());
 		} else if (e instanceof KeyAgreementFinishedEvent) {
-			listener.runOnUiThread(new Runnable() {
+			listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 				@Override
 				public void run() {
 					mainProgressContainer.setVisibility(VISIBLE);
-					mainProgressTitle.setText(R.string.exchanging_contact_details);
+					mainProgressTitle.setText(
+							R.string.exchanging_contact_details);
 				}
 			});
 		}
@@ -309,9 +305,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
 				String input =
 						Base64.encodeToString(payloadEncoder.encode(payload),
 								0);
-				Bitmap bitmap =
-						QrCodeUtils.createQrCode(dm, input);
-				return bitmap;
+				return QrCodeUtils.createQrCode(dm, input);
 			}
 
 			@Override
@@ -328,7 +322,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
 	}
 
 	private void setQrCode(final Payload localPayload) {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				generateBitmapQR(localPayload);
@@ -337,7 +331,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
 	}
 
 	private void keyAgreementFailed() {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				reset();
@@ -349,7 +343,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
 	}
 
 	private void keyAgreementWaiting() {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				status.setText(R.string.waiting_for_contact);
@@ -358,7 +352,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
 	}
 
 	private void keyAgreementStarted() {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				mainProgressContainer.setVisibility(VISIBLE);
@@ -368,7 +362,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
 	}
 
 	private void keyAgreementAborted(final boolean remoteAborted) {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				reset();
@@ -385,7 +379,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
 
 	@Override
 	public void handleResult(final Result result) {
-		listener.runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				LOG.info("Got result from decoder");
diff --git a/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java b/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java
index 893ea91262..286e0616dc 100644
--- a/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java
+++ b/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java
@@ -46,10 +46,8 @@ import static org.briarproject.api.sharing.SharingConstants.GROUP_ID;
 public class ContactSelectorFragment extends BaseFragment implements
 		BaseContactListAdapter.OnItemClickListener {
 
-	public final static String TAG = "ContactSelectorFragment";
-
-	private static final Logger LOG =
-			Logger.getLogger(ContactSelectorFragment.class.getName());
+	public static final String TAG = ContactSelectorFragment.class.getName();
+	private static final Logger LOG = Logger.getLogger(TAG);
 
 	private ShareActivity shareActivity;
 	private Menu menu;
@@ -84,12 +82,7 @@ public class ContactSelectorFragment extends BaseFragment implements
 	@Override
 	public void onAttach(Context context) {
 		super.onAttach(context);
-		try {
-			shareActivity = (ShareActivity) context;
-		} catch (ClassCastException e) {
-			throw new InstantiationError(
-					"This fragment is only meant to be attached to a subclass of ShareActivity");
-		}
+		shareActivity = (ShareActivity) context;
 	}
 
 	@Override
@@ -221,7 +214,7 @@ public class ContactSelectorFragment extends BaseFragment implements
 	}
 
 	private void displayContacts(final List<ContactListItem> contacts) {
-		shareActivity.runOnUiThread(new Runnable() {
+		shareActivity.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				if (!contacts.isEmpty()) adapter.addAll(contacts);
diff --git a/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java b/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java
index c7d99b14bd..941dbb48f1 100644
--- a/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java
+++ b/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java
@@ -32,7 +32,7 @@ abstract class InvitationsActivity extends BriarActivity
 	private BriarRecyclerView list;
 
 	@Inject
-	protected EventBus eventBus;
+	EventBus eventBus;
 
 	@Override
 	public void onCreate(Bundle state) {
@@ -103,7 +103,7 @@ abstract class InvitationsActivity extends BriarActivity
 
 	protected void displayInvitations(
 			final Collection<InvitationItem> invitations, final boolean clear) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				if (invitations.isEmpty()) {
diff --git a/briar-android/src/org/briarproject/android/sharing/ShareBlogMessageFragment.java b/briar-android/src/org/briarproject/android/sharing/ShareBlogMessageFragment.java
index f981602996..d9f944ab0c 100644
--- a/briar-android/src/org/briarproject/android/sharing/ShareBlogMessageFragment.java
+++ b/briar-android/src/org/briarproject/android/sharing/ShareBlogMessageFragment.java
@@ -14,6 +14,7 @@ import org.briarproject.api.db.DbException;
 import org.briarproject.api.sync.GroupId;
 
 import java.util.Collection;
+import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
@@ -23,6 +24,7 @@ import static java.util.logging.Level.WARNING;
 public class ShareBlogMessageFragment extends ShareMessageFragment {
 
 	public final static String TAG = ShareBlogMessageFragment.class.getName();
+	private static final Logger LOG = Logger.getLogger(TAG);
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject
@@ -52,6 +54,12 @@ public class ShareBlogMessageFragment extends ShareMessageFragment {
 		component.inject(this);
 	}
 
+	@Override
+	public String getUniqueTag() {
+		return TAG;
+	}
+
+	@Override
 	protected void share(final String msg) {
 		listener.runOnDbThread(new Runnable() {
 			@Override
@@ -69,8 +77,9 @@ public class ShareBlogMessageFragment extends ShareMessageFragment {
 		});
 	}
 
+	@Override
 	protected void sharingError() {
-		runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				int res = R.string.blogs_sharing_error;
diff --git a/briar-android/src/org/briarproject/android/sharing/ShareForumMessageFragment.java b/briar-android/src/org/briarproject/android/sharing/ShareForumMessageFragment.java
index f24869467a..8414096f01 100644
--- a/briar-android/src/org/briarproject/android/sharing/ShareForumMessageFragment.java
+++ b/briar-android/src/org/briarproject/android/sharing/ShareForumMessageFragment.java
@@ -14,6 +14,7 @@ import org.briarproject.api.forum.ForumSharingManager;
 import org.briarproject.api.sync.GroupId;
 
 import java.util.Collection;
+import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
@@ -23,6 +24,7 @@ import static java.util.logging.Level.WARNING;
 public class ShareForumMessageFragment extends ShareMessageFragment {
 
 	public final static String TAG = ShareForumMessageFragment.class.getName();
+	private static final Logger LOG = Logger.getLogger(TAG);
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject
@@ -49,6 +51,12 @@ public class ShareForumMessageFragment extends ShareMessageFragment {
 		component.inject(this);
 	}
 
+	@Override
+	public String getUniqueTag() {
+		return TAG;
+	}
+
+	@Override
 	protected void share(final String msg) {
 		listener.runOnDbThread(new Runnable() {
 			@Override
@@ -67,8 +75,9 @@ public class ShareForumMessageFragment extends ShareMessageFragment {
 		});
 	}
 
+	@Override
 	protected void sharingError() {
-		runOnUiThread(new Runnable() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				int res = R.string.forum_share_error;
diff --git a/briar-android/src/org/briarproject/android/sharing/ShareMessageFragment.java b/briar-android/src/org/briarproject/android/sharing/ShareMessageFragment.java
index 0df394e1f8..5a8f474763 100644
--- a/briar-android/src/org/briarproject/android/sharing/ShareMessageFragment.java
+++ b/briar-android/src/org/briarproject/android/sharing/ShareMessageFragment.java
@@ -18,7 +18,6 @@ import org.briarproject.api.sync.GroupId;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
@@ -29,10 +28,6 @@ import static org.briarproject.api.sharing.SharingConstants.GROUP_ID;
 abstract class ShareMessageFragment extends BaseFragment
 		implements TextInputListener {
 
-	public final static String TAG = ShareMessageFragment.class.getName();
-
-	protected static final Logger LOG = Logger.getLogger(TAG);
-
 	protected ViewHolder ui;
 	private ShareActivity shareActivity;
 
@@ -56,12 +51,7 @@ abstract class ShareMessageFragment extends BaseFragment
 	@Override
 	public void onAttach(Context context) {
 		super.onAttach(context);
-		try {
-			shareActivity = (ShareActivity) context;
-		} catch (ClassCastException e) {
-			throw new InstantiationError(
-					"This fragment is only meant to be attached to the ShareForumActivity");
-		}
+		shareActivity = (ShareActivity) context;
 	}
 
 	@Override
@@ -104,11 +94,6 @@ abstract class ShareMessageFragment extends BaseFragment
 		}
 	}
 
-	@Override
-	public String getUniqueTag() {
-		return TAG;
-	}
-
 	protected void setTitle(int res) {
 		shareActivity.setTitle(res);
 	}
@@ -136,10 +121,6 @@ abstract class ShareMessageFragment extends BaseFragment
 		return groupId;
 	}
 
-	protected void runOnUiThread(Runnable runnable) {
-		listener.runOnUiThread(runnable);
-	}
-
 	protected static class ViewHolder {
 		protected final LargeTextInputView message;
 
diff --git a/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java b/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java
index 422a7d16d8..969d525a3f 100644
--- a/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java
+++ b/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java
@@ -27,16 +27,16 @@ import static java.util.logging.Level.WARNING;
 
 abstract class SharingStatusActivity extends BriarActivity {
 
+	private static final Logger LOG =
+			Logger.getLogger(SharingStatusActivity.class.getName());
+
 	private GroupId groupId;
 	private BriarRecyclerView sharedByList, sharedWithList;
 	private SharingStatusAdapter sharedByAdapter, sharedWithAdapter;
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject
-	protected volatile IdentityManager identityManager;
-
-	public final static String TAG = SharingStatusActivity.class.getName();
-	private static final Logger LOG = Logger.getLogger(TAG);
+	volatile IdentityManager identityManager;
 
 	@Override
 	public void onCreate(Bundle savedInstanceState) {
@@ -120,7 +120,7 @@ abstract class SharingStatusActivity extends BriarActivity {
 	}
 
 	private void displaySharedBy(final List<ContactListItem> contacts) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				if (contacts.isEmpty()) {
@@ -156,7 +156,7 @@ abstract class SharingStatusActivity extends BriarActivity {
 	}
 
 	private void displaySharedWith(final List<ContactListItem> contacts) {
-		runOnUiThread(new Runnable() {
+		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
 				if (contacts.isEmpty()) {
diff --git a/briar-android/src/org/briarproject/android/view/TextInputView.java b/briar-android/src/org/briarproject/android/view/TextInputView.java
index e005624d2a..da1e58969a 100644
--- a/briar-android/src/org/briarproject/android/view/TextInputView.java
+++ b/briar-android/src/org/briarproject/android/view/TextInputView.java
@@ -24,17 +24,14 @@ import org.thoughtcrime.securesms.components.emoji.EmojiDrawer.EmojiEventListene
 import org.thoughtcrime.securesms.components.emoji.EmojiEditText;
 import org.thoughtcrime.securesms.components.emoji.EmojiToggle;
 
-import java.util.logging.Logger;
-
 import static android.content.Context.INPUT_METHOD_SERVICE;
+import static android.content.Context.LAYOUT_INFLATER_SERVICE;
+import static android.view.KeyEvent.KEYCODE_BACK;
 
 @UiThread
 public class TextInputView extends KeyboardAwareLinearLayout
 		implements EmojiEventListener {
 
-	private static final String TAG = TextInputView.class.getName();
-	private static final Logger LOG = Logger.getLogger(TAG);
-
 	protected final ViewHolder ui;
 	protected TextInputListener listener;
 
@@ -59,7 +56,7 @@ public class TextInputView extends KeyboardAwareLinearLayout
 
 	protected void inflateLayout(Context context) {
 		LayoutInflater inflater = (LayoutInflater) context
-				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+				.getSystemService(LAYOUT_INFLATER_SERVICE);
 		inflater.inflate(R.layout.text_input_view, this, true);
 	}
 
@@ -91,7 +88,7 @@ public class TextInputView extends KeyboardAwareLinearLayout
 		ui.editText.setOnKeyListener(new OnKeyListener() {
 			@Override
 			public boolean onKey(View v, int keyCode, KeyEvent event) {
-				if (keyCode == KeyEvent.KEYCODE_BACK && isEmojiDrawerOpen()) {
+				if (keyCode == KEYCODE_BACK && isEmojiDrawerOpen()) {
 					hideEmojiDrawer();
 					return true;
 				}
@@ -207,10 +204,11 @@ public class TextInputView extends KeyboardAwareLinearLayout
 	}
 
 	protected class ViewHolder {
+
 		private final EmojiToggle emojiToggle;
-		protected final EmojiEditText editText;
-		protected final View sendButton;
-		protected final EmojiDrawer emojiDrawer;
+		final EmojiEditText editText;
+		final View sendButton;
+		final EmojiDrawer emojiDrawer;
 
 		private ViewHolder() {
 			emojiToggle = (EmojiToggle) findViewById(R.id.emoji_toggle);
-- 
GitLab