Skip to content

Instantly share code, notes, and snippets.

@brescia123
Last active March 4, 2019 16:50
Show Gist options
  • Save brescia123/10f8c935984272fea2c7263c1d77465d to your computer and use it in GitHub Desktop.
Save brescia123/10f8c935984272fea2c7263c1d77465d to your computer and use it in GitHub Desktop.
Main components for lifecycle-aware presenters
import java.lang.ref.WeakReference
/**
* Base Interface for all the presenters.
*
* @param T The type of view (which extends [View]) the presenter is controlling.
*/
interface PresenterApi<in T : View> {
fun onAttach(v: T)
fun onDetach()
}
/** Base Class for all the presenters. It takes care of implementing the attach/detach view mechanism. */
abstract class Presenter<T : View> : PresenterApi<T> {
/** holds the view reference when it is attached. if the Presenter is not attached ot any View it is null. */
private var viewRef: WeakReference<T>? = null
/** convenient method to get the View */
fun view(): T? = viewRef?.get()
/**
* This method should be called every time a View is attached to the Presenter (e.g. configuration changes)
* or it is re-created. Here the presenter should render the view.
* (typically within onStart())
*
* @param v the [View] to be attached
*/
override fun onAttach(v: T) {
this.viewRef = WeakReference(v)
}
/**
* This method should be called every time the View is detached from the Presenter (e.g. configuration changes).
* (typically within onStop())
*/
override fun onDetach() {
viewRef?.clear()
viewRef = null
}
}
/** Base Interface for all the components (Activities, Fragments..) that act as views in MVP. */
interface View
import android.os.Bundle
import android.support.v4.app.LoaderManager
import android.support.v4.content.Loader
import android.support.v7.app.AppCompatActivity
abstract class PresenterActivity<V : View, P : Presenter<V>> : AppCompatActivity() {
protected var presenter: P? = null
abstract val presenterGenerator: () -> P
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
supportLoaderManager.initLoader(101, null, object : LoaderManager.LoaderCallbacks<P> {
override fun onCreateLoader(id: Int, args: Bundle?): Loader<P> {
return PresenterLoader(
this@PresenterActivity,
presenterGenerator)
}
override fun onLoadFinished(loader: Loader<P>, data: P) {
presenter = data
}
override fun onLoaderReset(loader: Loader<P>) {
presenter?.onDestroy()
presenter = null
}
})
}
override fun onStart() {
super.onStart()
presenter?.onAttach(this as V)
}
override fun onStop() {
presenter?.onDetach()
super.onStop()
}
override fun onDestroy() {
super.onDestroy()
presenter?.onDestroy()
}
}
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.app.LoaderManager
import android.support.v4.content.Loader
/** Base Activity ensuring that the given Presenter is detached form the the Activity lifecycle */
abstract class PresenterFragment<V : View, P : Presenter<V>> : Fragment() {
/** Factory function that has to be implemented by subclasses to provide a Presenter */
abstract val presenterGenerator: () -> P
protected var presenter: P? = null
private val loaderCallbacks: LoaderManager.LoaderCallbacks<P> = object : LoaderManager.LoaderCallbacks<P> {
override fun onCreateLoader(id: Int, args: Bundle?): Loader<P> =
PresenterLoader(context, presenterGenerator)
override fun onLoadFinished(loader: Loader<P>, data: P) {
presenter = data
}
override fun onLoaderReset(loader: Loader<P>) {
presenter = null
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
loaderManager.initLoader(101, null, loaderCallbacks)
}
override fun onStart() {
super.onStart()
presenter?.onAttach(this as V)
}
override fun onStop() {
presenter?.onDetach()
super.onStop()
}
}
import android.content.Context
import android.support.v4.content.Loader
/** Android Loader used to decouple [Presenter] from Activity/Fragment lifecycle. */
class PresenterLoader<T : Presenter<*>>(context: Context, private val factory: () -> T) : Loader<T>(context) {
private var presenter: T? = null
override fun onStartLoading() {
if (presenter != null)
deliverResult(presenter as T)
else
forceLoad()
}
override fun onForceLoad() {
presenter = factory()
deliverResult(presenter as T)
}
override fun onReset() {
presenter = null
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment