2015-08-11 12 views
15

Nella mia app io lavoro con ContentProvider e utilizzare LoaderManager.LoaderCallbacks<Cursor>.Android MVP: utilizzo sicuro contesto in Presenter

Fragment (Visualizza)

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; 
    } 

} 

Dal punto di vista MVP ho bisogno:

Presenter

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) 
    } 

} 

Quindi, ho bisogno di un contesto in Presenter.

ci sono alcune sfumature:

  1. Presenter sappiamo del contesto - è male, Presenter non dovrebbe conoscere l'Android.

  2. Avere un contesto in Presenter può causare perdite di memoria.

io sono ora preoccupati per come evitare problemi come perdite di memoria, e il modo migliore passare al contesto in Presenter, utilizzare contesto applicativo o Attività/Frammento?

+1

contesto App è la strada da percorrere. Se la vista ha bisogno del contesto di attività, può memorizzarla da sola (passata nel costruttore), ma assicurati di non mantenere un riferimento forte alla vista (a prescindere) se il tuo relatore sopravvive all'attività/frammento. – JohanShogun

+0

Un altro pensiero è che potresti consentire alla tua attività/frammento di assumere il ruolo del presentatore. A me sembra che tu abbia fatto in modo che il tuo frammento assuma il ruolo della vista, che è un po 'strano come la funzionalità di base del frammento piuttosto che quella del presentatore. La tua vista è nei file xml e visualizza sottoclassi. – JohanShogun

+0

Grazie per il feedback. Ho una situazione in cui parte la logica di business in Presenter (la parte più grande) e un'altra parte in Fragment (funziona con CursorLoader) e questo crea problemi. Voglio spostare tutta la logica aziendale in Presenter. – Alexandr

risposta

3

L'aggiunta di contesto a Presenter non va bene poiché il relatore è responsabile della logica aziendale. Per gestire il contesto, è necessario che il frammento/attività utilizzi le richiamate con l'aiuto di interfacce che stabiliscono quali azioni devono essere eseguite dall'attività/frammento quando si gestiscono le viste. Frammento/Attività sono responsabili di fornire contesto.

Esempio:

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. 
     } 
    } 
+1

potresti elaborare come funziona con i callback di Loaders come da domanda OP? – trocchietto

0

Proprio non si registra il tuo presentatore come Android target specifico di callback (ad esempio BroadcastReceiver, LoaderManager.LoaderCallbacks ecc). Gestisci i metodi di callback nella tua vista (Frammento o Attività) e passa tutti i dati relativi al relatore.

Se è necessario Context per la creazione dell'oggetto, consentire alla vista di creare questo oggetto (poiché ha un riferimento allo Context). Nel tuo caso la chiamata

Loader loader = new ArticleCatalogLoader(context, categoryId) 

dovrebbe essere riscritta per

view.createLoaderForCategory(categoryId) 
0

codice come questo

Loader loader = new ArticleCatalogLoader(context, categoryId); 

porta a codice non verificabile. Dovresti evitare di creare oggetti "business" nel tuo codice e lasciare che altri lo facciano per te (qualsiasi framework DI come Dagger 2 sarebbe un'opzione migliore che gestirlo tu stesso)

Detto questo, il tuo problema è qualcosa che DI ha risolto molto tempo fa. Hai bisogno di una nuova nuova istanza di qualsiasi oggetto? Utilizzare un Provider

A Provider è un oggetto che "fornisce" istanze di oggetti.Così, invece di avere

Loader loader = new ArticleCatalogLoader(context, categoryId); 

si avrà

Loader loader = loaderProvider.get(categoryId); 

Quindi l'unica cosa che serve è qualcosa di simile:

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; 
    } 

} 
Problemi correlati