diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index fa10b50859672779aaf7a82b165c24e6a7c2ba50..4bc36f436e069b8cec8eb9461a151048c578486a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -13,7 +13,7 @@
     android:supportsRtl="true"
     android:theme="@style/Theme.SplashTheme">
     <activity
-      android:name=".ui.ChatActivity"
+      android:name=".ui.chat.ChatActivity"
       android:exported="false"
       android:label="@string/app_name"
       android:windowSoftInputMode="adjustResize" />
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/service/QuasselService.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/service/QuasselService.kt
index a1b4123ec452ddb8e8e6c225071ecb60a5c8d54c..b2f8a35c0facb7f58ca20b1f66e9325b4094e305 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/service/QuasselService.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/service/QuasselService.kt
@@ -3,8 +3,6 @@ package de.kuschku.quasseldroid_ng.service
 import android.arch.lifecycle.LifecycleService
 import android.content.Intent
 import android.os.Binder
-import android.os.Handler
-import android.os.HandlerThread
 import de.kuschku.libquassel.protocol.*
 import de.kuschku.libquassel.session.Backend
 import de.kuschku.libquassel.session.SessionManager
@@ -13,6 +11,7 @@ import de.kuschku.quasseldroid_ng.BuildConfig
 import de.kuschku.quasseldroid_ng.R
 import de.kuschku.quasseldroid_ng.persistence.PersistentSession
 import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase
+import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread
 import de.kuschku.quasseldroid_ng.util.compatibility.AndroidHandlerService
 import org.threeten.bp.Instant
 import java.security.cert.X509Certificate
@@ -36,6 +35,12 @@ class QuasselService : LifecycleService() {
   private val backendImplementation = object : Backend {
     override fun sessionManager() = sessionManager
 
+    override fun connectUnlessConnected(address: SocketAddress, user: String, pass: String) {
+      sessionManager.ifDisconnected {
+        this.connect(address, user, pass)
+      }
+    }
+
     override fun connect(address: SocketAddress, user: String, pass: String) {
       disconnect()
       val handlerService = AndroidHandlerService()
@@ -47,10 +52,15 @@ class QuasselService : LifecycleService() {
     }
   }
 
-  private val thread = HandlerThread("BackendHandler")
-  private lateinit var handler: Handler
+  private val handler = AndroidHandlerThread("Backend")
 
   private val asyncBackend = object : Backend {
+    override fun connectUnlessConnected(address: SocketAddress, user: String, pass: String) {
+      handler.post {
+        backendImplementation.connectUnlessConnected(address, user, pass)
+      }
+    }
+
     override fun connect(address: SocketAddress, user: String, pass: String) {
       handler.post {
         backendImplementation.connect(address, user, pass)
@@ -67,15 +77,14 @@ class QuasselService : LifecycleService() {
   }
 
   override fun onDestroy() {
-    handler.post { thread.quit() }
+    handler.onDestroy()
     super.onDestroy()
   }
 
   private lateinit var database: QuasselDatabase
 
   override fun onCreate() {
-    thread.start()
-    handler = Handler(thread.looper)
+    handler.onCreate()
     super.onCreate()
     database = QuasselDatabase.Creator.init(application)
     sessionManager = SessionManager(PersistentSession())
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/ChatActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt
similarity index 63%
rename from app/src/main/java/de/kuschku/quasseldroid_ng/ui/ChatActivity.kt
rename to app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt
index e9bf43aaed72769a5f83cddfe2aab6dbdcd67975..b77956e67eb352bc2e4453cf27c9698fe3049195 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/ChatActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt
@@ -1,11 +1,9 @@
-package de.kuschku.quasseldroid_ng.ui
+package de.kuschku.quasseldroid_ng.ui.chat
 
 import android.app.Activity
 import android.arch.lifecycle.Observer
 import android.content.Context
 import android.os.Bundle
-import android.os.Handler
-import android.os.HandlerThread
 import android.support.design.widget.Snackbar
 import android.support.v7.widget.Toolbar
 import android.util.Log
@@ -17,25 +15,21 @@ import butterknife.BindView
 import butterknife.ButterKnife
 import de.kuschku.libquassel.session.*
 import de.kuschku.libquassel.util.compatibility.LoggingHandler
-import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.ERROR
 import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.INFO
-import de.kuschku.libquassel.util.compatibility.log
 import de.kuschku.quasseldroid_ng.Keys
 import de.kuschku.quasseldroid_ng.R
 import de.kuschku.quasseldroid_ng.persistence.AccountDatabase
-import de.kuschku.quasseldroid_ng.util.helper.*
+import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread
+import de.kuschku.quasseldroid_ng.util.helper.editApply
+import de.kuschku.quasseldroid_ng.util.helper.map
+import de.kuschku.quasseldroid_ng.util.helper.observeSticky
+import de.kuschku.quasseldroid_ng.util.helper.switchMapRx
 import de.kuschku.quasseldroid_ng.util.service.ServiceBoundActivity
 import org.threeten.bp.ZoneOffset
 import org.threeten.bp.ZonedDateTime
 import org.threeten.bp.format.DateTimeFormatter
 
 class ChatActivity : ServiceBoundActivity() {
-  @BindView(R.id.connect)
-  lateinit var connect: Button
-
-  @BindView(R.id.disconnect)
-  lateinit var disconnect: Button
-
   @BindView(R.id.clear)
   lateinit var clear: Button
 
@@ -45,12 +39,10 @@ class ChatActivity : ServiceBoundActivity() {
   @BindView(R.id.toolbar)
   lateinit var toolbar: Toolbar
 
-  private val thread = HandlerThread("Chat")
-  private lateinit var handler: Handler
+  private val handler = AndroidHandlerThread("Chat")
 
   private val sessionManager = backend.map(Backend::sessionManager)
-  private val state
-    = sessionManager.switchMapRx(SessionManager::state)
+  private val state = sessionManager.switchMapRx(SessionManager::state)
 
   private val bufferViewManager
     = sessionManager.switchMapRx(SessionManager::session).map(ISession::bufferViewManager)
@@ -62,13 +54,10 @@ class ChatActivity : ServiceBoundActivity() {
     }
   }
 
-  private
-  var snackbar: Snackbar? = null
+  private var snackbar: Snackbar? = null
 
-  private
-  val dateTimeFormatter: DateTimeFormatter = DateTimeFormatter.ISO_TIME
-  private
-  val logHandler = object : LoggingHandler() {
+  private val dateTimeFormatter: DateTimeFormatter = DateTimeFormatter.ISO_TIME
+  private val logHandler = object : LoggingHandler() {
     override fun log(logLevel: LogLevel, tag: String, message: String?,
                      throwable: Throwable?) {
       val time = dateTimeFormatter.format(ZonedDateTime.now(ZoneOffset.UTC))
@@ -99,46 +88,37 @@ class ChatActivity : ServiceBoundActivity() {
     super.onSaveInstanceState(outState)
   }
 
-  var account: AccountDatabase.Account? = null
-
   override fun onCreate(savedInstanceState: Bundle?) {
-    thread.start()
-    handler = Handler(thread.looper)
-
+    handler.onCreate()
     super.onCreate(savedInstanceState)
     setContentView(R.layout.activity_main)
     ButterKnife.bind(this)
     setSupportActionBar(toolbar)
 
-    val database = AccountDatabase.Creator.init(this)
-    handler.post {
-      val accountId = getSharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE)
-        ?.getLong(Keys.Status.selectedAccount, -1) ?: -1
-      if (accountId == -1L) {
-        setResult(Activity.RESULT_OK)
-        finish()
-      }
-      val it = database.accounts().findById(accountId)
-      if (it == null) {
-        setResult(Activity.RESULT_OK)
-        finish()
+    backend.observeSticky(this, Observer { backendValue ->
+      if (backendValue != null) {
+        val database = AccountDatabase.Creator.init(this)
+        handler.post {
+          val accountId = getSharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE)
+            ?.getLong(Keys.Status.selectedAccount, -1) ?: -1
+          if (accountId == -1L) {
+            setResult(Activity.RESULT_OK)
+            finish()
+          }
+          val account = database.accounts().findById(accountId)
+          if (account == null) {
+            setResult(Activity.RESULT_OK)
+            finish()
+          } else {
+            backendValue.connectUnlessConnected(
+              SocketAddress(account.host, account.port.toShort()),
+              account.user,
+              account.pass
+            )
+          }
+        }
       }
-      account = it
-    }
-
-    connect.setOnClickListener {
-      val account = account
-      if (account != null)
-        backend.value?.connect(
-          SocketAddress(account.host, account.port.toShort()),
-          account.user,
-          account.pass
-        )
-    }
-
-    disconnect.setOnClickListener {
-      backend.value?.disconnect()
-    }
+    })
 
     clear.setOnClickListener {
       errorList.text = ""
@@ -146,22 +126,11 @@ class ChatActivity : ServiceBoundActivity() {
 
     state.observeSticky(this, Observer {
       val status = it ?: ConnectionState.DISCONNECTED
-      val disconnected = status == ConnectionState.DISCONNECTED
-
-      disconnect.isEnabled = !disconnected
-      connect.isEnabled = disconnected
 
       snackbar?.dismiss()
       snackbar = Snackbar.make(errorList, status.name, Snackbar.LENGTH_SHORT)
       snackbar?.show()
     })
-
-    bufferViewManager.observeSticky(this, Observer {
-      log(ERROR, "bufferViewManager", it.toString())
-    })
-    bufferViewConfigs.or(emptyList()).observeSticky(this, Observer {
-      log(ERROR, "bufferViewConfigs", it.toString())
-    })
   }
 
   override fun onCreateOptionsMenu(menu: Menu?): Boolean {
@@ -171,11 +140,14 @@ class ChatActivity : ServiceBoundActivity() {
 
   override fun onOptionsItemSelected(item: MenuItem?) = when (item?.itemId) {
     R.id.disconnect -> {
-      getSharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE).editApply {
-        putBoolean(Keys.Status.reconnect, false)
+      handler.post {
+        getSharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE).editApply {
+          putBoolean(Keys.Status.reconnect, false)
+        }
+        backend.value?.disconnect()
+        setResult(Activity.RESULT_OK)
+        finish()
       }
-      setResult(Activity.RESULT_OK)
-      finish()
       true
     }
     else            -> super.onOptionsItemSelected(item)
@@ -186,6 +158,11 @@ class ChatActivity : ServiceBoundActivity() {
     LoggingHandler.loggingHandlers.add(logHandler)
   }
 
+  override fun onDestroy() {
+    handler.onDestroy()
+    super.onDestroy()
+  }
+
   override fun onStop() {
     LoggingHandler.loggingHandlers.remove(logHandler)
     super.onStop()
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatDelegate.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatDelegate.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9bd77701a8d8e8703de860fd2bede8b2e3da2b52
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatDelegate.kt
@@ -0,0 +1,3 @@
+package de.kuschku.quasseldroid_ng.ui.chat
+
+class ChatDelegate
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatListDelegate.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatListDelegate.kt
new file mode 100644
index 0000000000000000000000000000000000000000..13a9fa6662bd17ef7e6b37e906d23eb000ede531
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatListDelegate.kt
@@ -0,0 +1,3 @@
+package de.kuschku.quasseldroid_ng.ui.chat
+
+class ChatListDelegate
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/EditorDelegate.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/EditorDelegate.kt
new file mode 100644
index 0000000000000000000000000000000000000000..936c10251e84a1613110a19f9c5a174f13c91005
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/EditorDelegate.kt
@@ -0,0 +1,3 @@
+package de.kuschku.quasseldroid_ng.ui.chat
+
+class EditorDelegate
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/NickListDelegate.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/NickListDelegate.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1bb9509be2604a846961ea10d958e0caff38ef7f
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/NickListDelegate.kt
@@ -0,0 +1,3 @@
+package de.kuschku.quasseldroid_ng.ui.chat
+
+class NickListDelegate
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountEditActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountEditActivity.kt
index ba542dabb28e7fb112e95459a0ba371aef5e8cc0..43cfa75c73b155613afa5120f4c7fd5bd1961b58 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountEditActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountEditActivity.kt
@@ -3,8 +3,6 @@ package de.kuschku.quasseldroid_ng.ui.setup.accounts
 import android.app.Activity
 import android.content.Context
 import android.os.Bundle
-import android.os.Handler
-import android.os.HandlerThread
 import android.support.design.widget.TextInputEditText
 import android.support.design.widget.TextInputLayout
 import android.support.v7.app.AlertDialog
@@ -17,6 +15,7 @@ import butterknife.ButterKnife
 import de.kuschku.quasseldroid_ng.Keys
 import de.kuschku.quasseldroid_ng.R
 import de.kuschku.quasseldroid_ng.persistence.AccountDatabase
+import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread
 import de.kuschku.quasseldroid_ng.util.Patterns
 import de.kuschku.quasseldroid_ng.util.TextValidator
 import de.kuschku.quasseldroid_ng.util.helper.editCommit
@@ -51,13 +50,10 @@ class AccountEditActivity : AppCompatActivity() {
   private var account: AccountDatabase.Account? = null
   lateinit var database: AccountDatabase
 
-  private val thread = HandlerThread("AccountEdit")
-  private lateinit var handler: Handler
+  private val handler = AndroidHandlerThread("AccountEdit")
 
   override fun onCreate(savedInstanceState: Bundle?) {
-    thread.start()
-    handler = Handler(thread.looper)
-
+    handler.onCreate()
     setTheme(R.style.Theme_AppTheme_Light)
     super.onCreate(savedInstanceState)
     setContentView(R.layout.setup_account_edit)
@@ -136,7 +132,7 @@ class AccountEditActivity : AppCompatActivity() {
   }
 
   override fun onDestroy() {
-    handler.post { thread.quit() }
+    handler.onDestroy()
     super.onDestroy()
   }
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionActivity.kt
index e446387990f08a35c71e00a9ed2ce963abb0db6e..ec5e12e1cc664ea2d12ebfffb2c1920e0655690c 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionActivity.kt
@@ -6,7 +6,7 @@ import android.content.Intent
 import android.content.SharedPreferences
 import android.os.Bundle
 import de.kuschku.quasseldroid_ng.Keys
-import de.kuschku.quasseldroid_ng.ui.ChatActivity
+import de.kuschku.quasseldroid_ng.ui.chat.ChatActivity
 import de.kuschku.quasseldroid_ng.ui.setup.SetupActivity
 import de.kuschku.quasseldroid_ng.util.helper.editCommit
 
@@ -27,7 +27,7 @@ class AccountSelectionActivity : SetupActivity() {
       putLong(Keys.Status.selectedAccount, data.getLong(Keys.Status.selectedAccount, -1))
       putBoolean(Keys.Status.reconnect, true)
     }
-    startActivity(Intent(this, ChatActivity::class.java))
+    startActivityForResult(Intent(this, ChatActivity::class.java), REQUEST_CHAT)
   }
 
   override fun onCreate(savedInstanceState: Bundle?) {
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSetupActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSetupActivity.kt
index 35921bb0e213bd8184ec9659366fbfee835805d0..816786b5893dfe70bb03af07748abb3d4746a8e4 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSetupActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSetupActivity.kt
@@ -2,15 +2,13 @@ package de.kuschku.quasseldroid_ng.ui.setup.accounts
 
 import android.app.Activity
 import android.os.Bundle
-import android.os.Handler
-import android.os.HandlerThread
 import de.kuschku.quasseldroid_ng.persistence.AccountDatabase
 import de.kuschku.quasseldroid_ng.ui.setup.SetupActivity
+import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread
 import org.threeten.bp.Instant
 
 class AccountSetupActivity : SetupActivity() {
-  private val thread = HandlerThread("Setup")
-  private lateinit var handler: Handler
+  private val handler = AndroidHandlerThread("Setup")
 
   override fun onDone(data: Bundle) {
     val account = AccountDatabase.Account(
@@ -23,7 +21,7 @@ class AccountSetupActivity : SetupActivity() {
       lastUsed = Instant.now().epochSecond
     )
     handler.post {
-      val (id) = AccountDatabase.Creator.init(this).accounts().create(account)
+      AccountDatabase.Creator.init(this).accounts().create(account)
       runOnUiThread {
         setResult(Activity.RESULT_OK)
         finish()
@@ -32,13 +30,12 @@ class AccountSetupActivity : SetupActivity() {
   }
 
   override fun onCreate(savedInstanceState: Bundle?) {
-    thread.start()
-    handler = Handler(thread.looper)
+    handler.onCreate()
     super.onCreate(savedInstanceState)
   }
 
   override fun onDestroy() {
-    handler.post { thread.quit() }
+    handler.onDestroy()
     super.onDestroy()
   }
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidHandlerThread.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidHandlerThread.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4471116224ca3fb2ecd863c16df9a86a92687ae2
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidHandlerThread.kt
@@ -0,0 +1,135 @@
+package de.kuschku.quasseldroid_ng.util
+
+import android.os.Handler
+import android.os.HandlerThread
+import android.os.Looper
+import android.os.Message
+import android.util.Printer
+
+class AndroidHandlerThread(name: String) : HandlerThread(name) {
+  @Volatile
+  private var handler: Handler? = null
+
+  fun started(): AndroidHandlerThread {
+    onCreate()
+    return this
+  }
+
+  fun onCreate() {
+    if (handler == null) {
+      synchronized(this@AndroidHandlerThread) {
+        if (handler == null) {
+          start()
+          handler = Handler(looper)
+        }
+      }
+    }
+  }
+
+  fun onDestroy() {
+    if (handler != null) {
+      post {
+        quit()
+        if (handler != null) {
+          synchronized(this@AndroidHandlerThread) {
+            if (handler != null) {
+              handler = null
+            }
+          }
+        }
+      }
+    }
+  }
+
+  fun handleMessage(msg: Message)
+    = handler?.handleMessage(msg) ?: throw RuntimeException("Thread not started")
+
+  fun dispatchMessage(msg: Message)
+    = handler?.dispatchMessage(msg) ?: throw RuntimeException("Thread not started")
+
+  fun getMessageName(message: Message): String
+    = handler?.getMessageName(message) ?: throw RuntimeException("Thread not started")
+
+  fun obtainMessage(): Message
+    = handler?.obtainMessage() ?: throw RuntimeException("Thread not started")
+
+  fun obtainMessage(what: Int): Message
+    = handler?.obtainMessage(what) ?: throw RuntimeException("Thread not started")
+
+  fun obtainMessage(what: Int, obj: Any): Message
+    = handler?.obtainMessage(what, obj) ?: throw RuntimeException("Thread not started")
+
+  fun obtainMessage(what: Int, arg1: Int, arg2: Int): Message
+    = handler?.obtainMessage(what, arg1, arg2) ?: throw RuntimeException("Thread not started")
+
+  fun obtainMessage(what: Int, arg1: Int, arg2: Int, obj: Any): Message
+    = handler?.obtainMessage(what, arg1, arg2, obj) ?: throw RuntimeException("Thread not started")
+
+  fun post(r: () -> Unit): Boolean
+    = handler?.post(r) ?: throw RuntimeException("Thread not started")
+
+  fun postAtTime(r: () -> Unit, uptimeMillis: Long): Boolean
+    = handler?.postAtTime(r, uptimeMillis) ?: throw RuntimeException("Thread not started")
+
+  fun postAtTime(r: () -> Unit, token: Any, uptimeMillis: Long): Boolean
+    = handler?.postAtTime(r, token, uptimeMillis) ?: throw RuntimeException("Thread not started")
+
+  fun postDelayed(r: () -> Unit, delayMillis: Long): Boolean
+    = handler?.postDelayed(r, delayMillis) ?: throw RuntimeException("Thread not started")
+
+  fun postAtFrontOfQueue(r: () -> Unit): Boolean
+    = handler?.postAtFrontOfQueue(r) ?: throw RuntimeException("Thread not started")
+
+  fun removeCallbacks(r: () -> Unit)
+    = handler?.removeCallbacks(r) ?: throw RuntimeException("Thread not started")
+
+  fun removeCallbacks(r: () -> Unit, token: Any)
+    = handler?.removeCallbacks(r, token) ?: throw RuntimeException("Thread not started")
+
+  fun sendMessage(msg: Message): Boolean
+    = handler?.sendMessage(msg) ?: throw RuntimeException("Thread not started")
+
+  fun sendEmptyMessage(what: Int): Boolean
+    = handler?.sendEmptyMessage(what) ?: throw RuntimeException("Thread not started")
+
+  fun sendEmptyMessageDelayed(what: Int, delayMillis: Long): Boolean
+    = handler?.sendEmptyMessageDelayed(what, delayMillis) ?: throw RuntimeException(
+    "Thread not started")
+
+  fun sendEmptyMessageAtTime(what: Int, uptimeMillis: Long): Boolean
+    = handler?.sendEmptyMessageAtTime(what, uptimeMillis) ?: throw RuntimeException(
+    "Thread not started")
+
+  fun sendMessageDelayed(msg: Message, delayMillis: Long): Boolean
+    = handler?.sendMessageDelayed(msg, delayMillis) ?: throw RuntimeException("Thread not started")
+
+  fun sendMessageAtTime(msg: Message, uptimeMillis: Long): Boolean
+    = handler?.sendMessageAtTime(msg, uptimeMillis) ?: throw RuntimeException("Thread not started")
+
+  fun sendMessageAtFrontOfQueue(msg: Message): Boolean
+    = handler?.sendMessageAtFrontOfQueue(msg) ?: throw RuntimeException("Thread not started")
+
+  fun removeMessages(what: Int)
+    = handler?.removeMessages(what) ?: throw RuntimeException("Thread not started")
+
+  fun removeMessages(what: Int, `object`: Any)
+    = handler?.removeMessages(what, `object`) ?: throw RuntimeException("Thread not started")
+
+  fun removeCallbacksAndMessages(token: Any)
+    = handler?.removeCallbacksAndMessages(token) ?: throw RuntimeException("Thread not started")
+
+  fun hasMessages(what: Int): Boolean
+    = handler?.hasMessages(what) ?: throw RuntimeException("Thread not started")
+
+  fun hasMessages(what: Int, `object`: Any): Boolean
+    = handler?.hasMessages(what, `object`) ?: throw RuntimeException("Thread not started")
+
+  val handlerLooper: Looper
+    get() = handler?.looper ?: throw RuntimeException("Thread not started")
+
+  fun dump(pw: Printer, prefix: String)
+    = handler?.dump(pw, prefix) ?: throw RuntimeException("Thread not started")
+
+  override fun toString(): String
+    = handler?.toString() ?: throw RuntimeException("Thread not started")
+}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index ebbea8d560a06dab78280fd5c9a774237fbfbc85..c5aac80009882180102c38b38ae04d4f8f2e9b7c 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -7,57 +7,89 @@
   android:fitsSystemWindows="true"
   tools:openDrawer="start">
 
-  <include layout="@layout/content_main" />
-
-  <de.kuschku.quasseldroid_ng.util.ui.DrawerRecyclerView
-    android:id="@+id/nickList"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_gravity="end"
-    android:background="?android:attr/windowBackground"
-    android:clipToPadding="false"
-    android:fitsSystemWindows="true" />
-
-  <de.kuschku.quasseldroid_ng.util.ui.NavigationDrawerLayout
+  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:layout_gravity="start"
-    android:background="?android:attr/windowBackground"
     android:fitsSystemWindows="true"
-    app:insetForeground="?attr/colorPrimaryDark">
+    android:orientation="vertical">
 
-    <LinearLayout
+    <android.support.design.widget.AppBarLayout
       android:layout_width="match_parent"
-      android:layout_height="match_parent"
-      android:orientation="vertical">
+      android:layout_height="wrap_content"
+      android:theme="?attr/actionBarTheme">
 
-      <android.support.design.widget.AppBarLayout
+      <android.support.v7.widget.Toolbar
+        android:id="@+id/toolbar"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:theme="?attr/actionBarTheme">
+        android:layout_height="?attr/actionBarSize"
+        android:background="?attr/colorPrimary"
+        app:contentInsetStartWithNavigation="0dp">
 
-        <android.support.v7.widget.Toolbar
-          android:id="@+id/toolbar"
-          android:layout_width="match_parent"
-          android:layout_height="?attr/actionBarSize"
-          android:background="?attr/colorPrimary"
-          app:contentInsetStartWithNavigation="0dp">
+        <LinearLayout
+          android:id="@+id/toolbar_action_area"
+          android:layout_width="fill_parent"
+          android:layout_height="fill_parent"
+          android:background="?attr/selectableItemBackgroundBorderless"
+          android:clickable="true"
+          android:focusable="true"
+          android:focusableInTouchMode="false"
+          android:gravity="center_vertical|start"
+          android:minHeight="?attr/actionBarSize"
+          android:orientation="vertical">
 
-          <android.support.v7.widget.AppCompatSpinner
-            android:id="@+id/chatListSpinner"
-            android:layout_width="fill_parent"
-            android:layout_height="match_parent"
-            android:theme="?attr/actionBarTheme" />
+          <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_marginTop="-2dp"
+            android:baselineAligned="false"
+            android:gravity="center_vertical">
 
-        </android.support.v7.widget.Toolbar>
+            <TextView
+              android:id="@+id/key"
+              style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
+              android:layout_width="16dp"
+              android:layout_height="16dp"
+              android:layout_marginEnd="2dp"
+              android:layout_marginRight="2dp"
+              android:layout_marginTop="2dp"
+              android:gravity="center"
+              android:textSize="16sp"
+              android:visibility="gone" />
 
-      </android.support.design.widget.AppBarLayout>
+            <TextView
+              android:id="@+id/toolbar_title"
+              style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:ellipsize="end"
+              android:gravity="center_vertical"
+              android:singleLine="true"
+              android:text="@string/app_name" />
 
+          </LinearLayout>
 
-      <android.support.v7.widget.RecyclerView
-        android:id="@+id/chatList"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-    </LinearLayout>
-  </de.kuschku.quasseldroid_ng.util.ui.NavigationDrawerLayout>
+          <TextView
+            android:id="@+id/toolbar_subtitle"
+            style="@style/TextAppearance.AppCompat.Widget.ActionBar.Subtitle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="-3dp"
+            android:ellipsize="end"
+            android:singleLine="true"
+            android:visibility="gone" />
+        </LinearLayout>
+
+      </android.support.v7.widget.Toolbar>
+
+    </android.support.design.widget.AppBarLayout>
+
+    <include layout="@layout/content_main" />
+
+  </LinearLayout>
+
+  <include layout="@layout/content_nicklist" />
+
+  <include layout="@layout/content_chatlist" />
 </android.support.v4.widget.DrawerLayout>
diff --git a/app/src/main/res/layout/content_chatlist.xml b/app/src/main/res/layout/content_chatlist.xml
new file mode 100644
index 0000000000000000000000000000000000000000..76715e8e3ce75d4254750d61c3bce2cdffcf2a8c
--- /dev/null
+++ b/app/src/main/res/layout/content_chatlist.xml
@@ -0,0 +1,43 @@
+<de.kuschku.quasseldroid_ng.util.ui.NavigationDrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
+  xmlns:app="http://schemas.android.com/apk/res-auto"
+  android:layout_width="match_parent"
+  android:layout_height="match_parent"
+  android:layout_gravity="start"
+  android:background="?android:attr/windowBackground"
+  android:fitsSystemWindows="true"
+  app:insetForeground="?attr/colorPrimaryDark">
+
+  <LinearLayout
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <android.support.design.widget.AppBarLayout
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:theme="?attr/actionBarTheme">
+
+      <android.support.v7.widget.Toolbar
+        android:id="@+id/chatListToolbar"
+        android:layout_width="match_parent"
+        android:layout_height="?attr/actionBarSize"
+        android:background="?attr/colorPrimary"
+        app:contentInsetStartWithNavigation="0dp">
+
+        <android.support.v7.widget.AppCompatSpinner
+          android:id="@+id/chatListSpinner"
+          android:layout_width="fill_parent"
+          android:layout_height="match_parent"
+          android:theme="?attr/actionBarTheme" />
+
+      </android.support.v7.widget.Toolbar>
+
+    </android.support.design.widget.AppBarLayout>
+
+
+    <android.support.v7.widget.RecyclerView
+      android:id="@+id/chatList"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent" />
+  </LinearLayout>
+</de.kuschku.quasseldroid_ng.util.ui.NavigationDrawerLayout>
diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml
index a4984d3789756b6101de591c7cd1159a7ddf92b1..8151d2669b8cc7c546e73ad70c3871e569665bc3 100644
--- a/app/src/main/res/layout/content_main.xml
+++ b/app/src/main/res/layout/content_main.xml
@@ -1,128 +1,33 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-  xmlns:app="http://schemas.android.com/apk/res-auto"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
-  android:layout_height="match_parent"
-  android:fitsSystemWindows="true"
-  android:orientation="vertical">
+  android:layout_height="match_parent">
 
-  <android.support.design.widget.AppBarLayout
+  <LinearLayout
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:theme="?attr/actionBarTheme">
-
-    <android.support.v7.widget.Toolbar
-      android:id="@+id/toolbar"
-      android:layout_width="match_parent"
-      android:layout_height="?attr/actionBarSize"
-      android:background="?attr/colorPrimary"
-      app:contentInsetStartWithNavigation="0dp">
-
-      <LinearLayout
-        android:id="@+id/toolbar_action_area"
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent"
-        android:background="?attr/selectableItemBackgroundBorderless"
-        android:clickable="true"
-        android:focusable="true"
-        android:focusableInTouchMode="false"
-        android:gravity="center_vertical|start"
-        android:minHeight="?attr/actionBarSize"
-        android:orientation="vertical">
-
-        <LinearLayout
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:layout_gravity="center_vertical"
-          android:layout_marginTop="-2dp"
-          android:baselineAligned="false"
-          android:gravity="center_vertical">
-
-          <TextView
-            android:id="@+id/key"
-            style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
-            android:layout_width="16dp"
-            android:layout_height="16dp"
-            android:layout_marginEnd="2dp"
-            android:layout_marginRight="2dp"
-            android:layout_marginTop="2dp"
-            android:gravity="center"
-            android:textSize="16sp"
-            android:visibility="gone" />
-
-          <TextView
-            android:id="@+id/toolbar_title"
-            style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:ellipsize="end"
-            android:gravity="center_vertical"
-            android:singleLine="true"
-            android:text="@string/app_name" />
-
-        </LinearLayout>
-
-        <TextView
-          android:id="@+id/toolbar_subtitle"
-          style="@style/TextAppearance.AppCompat.Widget.ActionBar.Subtitle"
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:layout_marginTop="-3dp"
-          android:ellipsize="end"
-          android:singleLine="true"
-          android:visibility="gone" />
-      </LinearLayout>
-
-    </android.support.v7.widget.Toolbar>
-
-  </android.support.design.widget.AppBarLayout>
-
-  <ScrollView
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_marginBottom="8dp"
+    android:layout_marginTop="8dp"
+    android:orientation="vertical"
+    android:paddingLeft="24dp"
+    android:paddingRight="24dp">
 
     <LinearLayout
       android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:layout_marginBottom="8dp"
-      android:layout_marginTop="8dp"
-      android:orientation="vertical"
-      android:paddingLeft="24dp"
-      android:paddingRight="24dp">
-
-      <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content">
-
-        <Button
-          android:id="@+id/connect"
-          style="@style/Widget.Button.Colored"
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:minWidth="88dp"
-          android:text="Connect" />
+      android:layout_height="wrap_content">
 
-        <Button
-          android:id="@+id/disconnect"
-          style="@style/Widget.Button"
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:minWidth="88dp"
-          android:text="Disconnect" />
-
-        <Button
-          android:id="@+id/clear"
-          style="@style/Widget.Button"
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:minWidth="88dp"
-          android:text="Clear" />
-      </LinearLayout>
-
-      <TextView
-        android:id="@+id/errorList"
-        android:layout_width="match_parent"
+      <Button
+        android:id="@+id/clear"
+        style="@style/Widget.Button"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:textIsSelectable="true" />
+        android:minWidth="88dp"
+        android:text="Clear" />
     </LinearLayout>
-  </ScrollView>
-</LinearLayout>
+
+    <TextView
+      android:id="@+id/errorList"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:textIsSelectable="true" />
+  </LinearLayout>
+</ScrollView>
diff --git a/app/src/main/res/layout/content_nicklist.xml b/app/src/main/res/layout/content_nicklist.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d056659f040debc25c381349d4aefcfcfdde0787
--- /dev/null
+++ b/app/src/main/res/layout/content_nicklist.xml
@@ -0,0 +1,8 @@
+<de.kuschku.quasseldroid_ng.util.ui.DrawerRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
+  android:id="@+id/nickList"
+  android:layout_width="match_parent"
+  android:layout_height="match_parent"
+  android:layout_gravity="end"
+  android:background="?android:attr/windowBackground"
+  android:clipToPadding="false"
+  android:fitsSystemWindows="true" />
diff --git a/lib/src/main/java/de/kuschku/libquassel/session/Backend.kt b/lib/src/main/java/de/kuschku/libquassel/session/Backend.kt
index a0535645b8d50bedab512b1252272b23e6f96d93..634d1da4583fe2748fb170377024c004f373c365 100644
--- a/lib/src/main/java/de/kuschku/libquassel/session/Backend.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/session/Backend.kt
@@ -1,6 +1,7 @@
 package de.kuschku.libquassel.session
 
 interface Backend {
+  fun connectUnlessConnected(address: SocketAddress, user: String, pass: String)
   fun connect(address: SocketAddress, user: String, pass: String)
   fun disconnect()
   fun sessionManager(): SessionManager
diff --git a/lib/src/main/java/de/kuschku/libquassel/session/SessionManager.kt b/lib/src/main/java/de/kuschku/libquassel/session/SessionManager.kt
index a90363ffa07ebab255cac266048141097b32a96a..935c503d775b384b1efb168e85145cb435aabf3c 100644
--- a/lib/src/main/java/de/kuschku/libquassel/session/SessionManager.kt
+++ b/lib/src/main/java/de/kuschku/libquassel/session/SessionManager.kt
@@ -49,6 +49,12 @@ class SessionManager(
     Invokers
   }
 
+  fun ifDisconnected(closure: () -> Unit) {
+    if (state.or(ConnectionState.DISCONNECTED) == ConnectionState.DISCONNECTED) {
+      closure()
+    }
+  }
+
   fun connect(
     clientData: ClientData,
     trustManager: X509TrustManager,
@@ -61,6 +67,7 @@ class SessionManager(
   }
 
   fun disconnect() {
+    inProgressSession.value
     inProgressSession.value.close()
     inProgressSession.onNext(offlineSession)
   }