Skip to content

Instantly share code, notes, and snippets.

@albodelu
Forked from ntoskrnl/Presenter.kt
Created October 8, 2017 08:33
Show Gist options
  • Save albodelu/57d610f6b04a32bae6ce4835a42e1b4d to your computer and use it in GitHub Desktop.
Save albodelu/57d610f6b04a32bae6ce4835a42e1b4d to your computer and use it in GitHub Desktop.
Android. Example of how to store presenter in retained fragment and enable it to persist and restore view state.
interface Presenter<in V, in R> {
fun create()
fun attachRouter(router: R)
fun attachView(view: V)
fun detachView()
fun detachRouter()
fun destroy()
}
import android.os.Bundle
interface PresenterProvider {
fun providePresenter(key: String, savedState: Bundle?): Presenter<*, *>
}
import android.content.Context
import android.os.Bundle
import android.support.v4.app.Fragment
class PresenterRetainedFragment() : Fragment() {
private var presenterProvider: PresenterProvider? = null
private val presenters = mutableMapOf<String, Presenter<*, *>>()
override fun onAttach(context: Context?) {
super.onAttach(context)
presenterProvider = context as? PresenterProvider
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
retainInstance = true
if (savedInstanceState != null) {
savedInstanceState.getStringArray("keys")
.filter { it !in presenters.keys }
.map { key ->
key to presenterProvider?.providePresenter(key, savedInstanceState.getBundle("$key.state"))
}
.forEach {
val (key, presenter) = it
if (presenter != null) {
presenters.put(key, presenter)
presenter.create()
}
}
}
}
override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
outState?.putStringArray("keys", presenters.keys.toTypedArray())
presenters.entries.forEach { entry ->
val (key, presenter) = entry
val state = Bundle()
(presenter as? StatefulPresenter)?.saveState(state)
outState?.putBundle("$key.state", state)
}
}
override fun onDestroy() {
if (isRemoving) {
presenters.values.forEach { it.destroy() }
presenters.clear()
}
super.onDestroy()
}
fun addPresenter(key: String, presenter: Presenter<*, *>) {
presenters[key] = presenter
}
fun getPresenter(key: String): Presenter<*, *>? {
return presenters[key]
}
}
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentActivity
import android.support.v4.app.FragmentManager
fun <P : Presenter<V, R>, V, R> FragmentManager.getOrCreatePresenter(key: String, provider: PresenterProvider): P {
var container = findFragmentByTag("presenters") as PresenterRetainedFragment?
if (container == null) {
container = PresenterRetainedFragment()
beginTransaction()
.add(container, "presenters")
.commitNow()
}
val foundPresenter = container.getPresenter(key)
return when (foundPresenter) {
null -> {
val newPresenter = provider.providePresenter(key, null)
container.addPresenter(key, newPresenter)
newPresenter.create()
@Suppress("UNCHECKED_CAST")
newPresenter as P
}
else -> {
@Suppress("UNCHECKED_CAST")
foundPresenter as P
}
}
}
fun <P : Presenter<V, R>, V, R> Fragment.getOrCreatePresenter(key: String): P {
return getOrCreatePresenter<P, V, R>(key, this as PresenterProvider)
}
fun <P : Presenter<V, R>, V, R> Fragment.getOrCreatePresenter(key: String, provider: PresenterProvider): P {
return fragmentManager.getOrCreatePresenter<P, V, R>(key, provider)
}
fun <P : Presenter<V, R>, V, R> FragmentActivity.getOrCreatePresenter(key: String): P {
return getOrCreatePresenter<P, V, R>(key, this as PresenterProvider)
}
fun <P : Presenter<V, R>, V, R> FragmentActivity.getOrCreatePresenter(key: String, provider: PresenterProvider): P {
return supportFragmentManager.getOrCreatePresenter<P, V, R>(key, provider)
}
import android.os.Bundle
interface StatefulPresenter {
fun saveState(state: Bundle)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment