Skip to content

Instantly share code, notes, and snippets.

@ntoskrnl
Last active January 20, 2017 21:25
Show Gist options
  • Save ntoskrnl/18f6d31e3ab83edbe5c763a0ca3d22e9 to your computer and use it in GitHub Desktop.
Save ntoskrnl/18f6d31e3ab83edbe5c763a0ca3d22e9 to your computer and use it in GitHub Desktop.
Container for presenters with persistent state
class PresenterRetainedFragment : Fragment() {
private val presenters = mutableMapOf<String, Any>()
private var savedState: Bundle? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
retainInstance = true
savedState = savedInstanceState
}
override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
presenters.entries.forEach { entry ->
val (key, presenter) = entry
val presenterState = (presenter as? Stateful)?.getPersistableState()
if (presenterState != null) {
outState?.putBundle("$key.presenter.state", presenterState)
}
}
}
override fun onDestroy() {
savedState = null
presenters.values.forEach { (it as? Destroyable)?.destroy() }
presenters.clear()
super.onDestroy()
}
fun <P : Any> getPresenter(key: String, presenterProvider: (Bundle?) -> P): P {
val presenter = presenters.getOrPut(
key = key,
defaultValue = {
val newPresenter = presenterProvider(savedState?.getBundle("$key.presenter.state"))
(newPresenter as? Presenter<*>)?.create()
newPresenter
}
)
@Suppress("UNCHECKED_CAST")
return presenter as P
}
fun removePresenter(key: String) {
savedState?.remove(key)
val presenter = presenters.remove(key)
if (presenter != null) {
(presenter as? Destroyable)?.destroy()
}
}
}
interface Presenter : Destroyable {
fun create()
override fun destroy()
}
interface Destroyable {
fun destroy()
}
interface Stateful {
fun getPersistableState(): Bundle?
}
private const val TAG = "__presenters__"
@SuppressLint("CommitTransaction")
fun <Presenter : Any> FragmentManager.getOrCreatePresenter(key: String, presenterProvider: (Bundle?) -> Presenter): Presenter {
var container = findFragmentByTag(TAG) as PresenterRetainedFragment?
if (container == null) {
container = PresenterRetainedFragment()
beginTransaction()
.add(container, TAG)
.commitNow()
}
return container.getPresenter(key, presenterProvider)
}
fun FragmentManager.removePresenter(key: String) {
val container = findFragmentByTag(TAG) as PresenterRetainedFragment?
container?.removePresenter(key)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment