MVP para Android: uso seguro Contexto en Presenter

En mi aplicación trabajo con ContentProvider y uso LoaderManager.LoaderCallbacks<Cursor>.

Fragmento (Ver)

 public class ArticleCatalogFragment extends BaseFragment implements ArticleCatalogPresenter.View, LoaderManager.LoaderCallbacks<Cursor> { @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { return onCreateArticleCatalogLoader(args); } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { data.registerContentObserver(new LoaderContentObserver(new Handler(), loader)); updateUI(data); } private Loader onCreateArticleCatalogLoader(Bundle args) { int categoryId = args.getInt(CATEGORY_ID); Loader loader = new ArticleCatalogLoader(this.getActivity(), categoryId); return loader; } } 

Desde el punto de vista MVP necesito:

Presentador

 public class ArticleCatalogPresenter extends BasePresenter implements LoaderManager.LoaderCallbacks<Cursor> { View view; @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { return onCreateArticleCatalogLoader(args); } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { data.registerContentObserver(new LoaderContentObserver(new Handler(), loader)); view.updateUI(data); } private Loader onCreateArticleCatalogLoader(Bundle args) { int categoryId = args.getInt(CATEGORY_ID); Loader loader = new ArticleCatalogLoader(context, categoryId); // need Context return loader; } interface View { updateUI(Cursor data) } } 

Por lo tanto, necesito un contexto en Presenter.

Hay algunos matices:

  1. Presentador saber sobre el contexto – es malo, presentador no debe saber sobre el Android.

  2. Tener un contexto en Presenter puede provocar una pérdida de memoria.

Ahora estoy preocupado acerca de cómo evitar problemas tales como fugas de memoria, y la mejor manera de pasar Contexto en Presenter, el uso de Contexto de Aplicación o Actividad / Fragmento?

Agregar contexto al presentador no es bueno ya que el presentador es responsable de la lógica de negocios. Para hacer frente al contexto, es necesario que el Fragmento / Actividades haga uso de las devoluciones de llamada con la ayuda de interfaces que indicarán qué acciones deben realizar la actividad / fragmento al tratar las vistas. Fragmento / Actividades son responsables de proveer Contexto.

Ejemplo:

 interface BaseContract { interface BaseView { //Methods for View void onDoSomething(); } interface BasePresenter { void doSomething(); } } class BaseMainPresenter implements BaseContract.BasePresenter { BaseContract.BaseView view; BaseMainPresenter(BaseContract.BaseView view) { this.view = view; } @Override public void doSomething() { if (view != null) view.onDoSomething(); } } class DemoClass implements BaseContract.BaseView { //Create object of Presenter /**** * Example : * BaseMainPresenter baseMainPresenter = new BaseMainPresenter(this); */ @Override public void onDoSomething() { //Deal with Context here. } } 

Simplemente no registre su presentador como objetivo de devolución de llamada específico de Android (por ejemplo, BroadcastReceiver , LoaderManager.LoaderCallbacks , etc.). Maneje los métodos de devolución de llamada en su vista (Fragmento o Actividad) y pase todos los datos relacionados al presentador.

Si necesita Context para la creación de objetos, deje que su vista cree este objeto (ya que tiene una referencia al Context ). En su caso la llamada

 Loader loader = new ArticleCatalogLoader(context, categoryId) 

debe ser refactorizado a

 view.createLoaderForCategory(categoryId) 

Código como este

 Loader loader = new ArticleCatalogLoader(context, categoryId); 

conduce a un untestable código. Debe evitar la creación de objetos "comerciales" en su código y dejar que cualquier persona lo haga por usted (cualquier marco DI como Dagger 2 sería una opción mejor que manejarlo usted mismo)

Dicho esto, su problema es algo que DI ha resuelto hace mucho tiempo. ¿Necesita una nueva instancia de cualquier objeto? Utilizar un Provider

Un Provider es un objeto que "proporciona" instancias de objetos. Así que en lugar de tener

 Loader loader = new ArticleCatalogLoader(context, categoryId); 

usted tendrá

 Loader loader = loaderProvider.get(categoryId); 

Así que lo único que necesitas es algo como esto:

 public class ArticleCatalogPresenter ... { ... private final Provider<Loader> loaderProvider; public ArticleCatalogPresenter(Provider<Loader> loaderProvider, ...) { this.loaderProvider = loaderProvider; ... } private Loader onCreateArticleCatalogLoader(Bundle args) { int categoryId = args.getInt(CATEGORY_ID); Loader loader = loaderProvider.get(categoryId); // no context needed anymore! return loader; } } 
  • ¿Cómo debo pasar los datos (por ejemplo, qué elemento se hizo clic) entre Actividades en MVP?
  • Android Dagger 2 y MVP se inyectan dentro de un objeto inyectado
  • Realización de Interactors con Android MVP Clean Architecture
  • Cómo controlar ListView con el patrón MVP para Android
  • Desventaja de MVP sobre patrón de diseño MVVM en android
  • Model View Presenter - misma vista, diferentes presentadores
  • MVP Android - ¿Dónde guardar el estado de vista?
  • Estructura en capas de Android clean architecture
  • ¿El desarrollo de la interfaz de usuario de Android se presta bien a un patrón de diseño participativo?
  • ¿Cómo compartir datos entre dos presentadores en la arquitectura MVP en Android?
  • MVP de Android: cómo comunicarse entre el presentador de la actividad y el presentador de fragmentos
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.