2012-03-29 10 views
5

Ciascuna delle mie attività necessita di un'attestazione di singleton Correspoding. Qual è la migliore strategia per iniettarli nelle attività?utilizzando GIN nelle attività GWT

  1. costruttore iniezione costruttore attività viene chiamato da getActivity di un ActivityMapper(). Il codificatore ha già un parametro (un oggetto Place). Dovrei creare ActivityMapper con tutte le possibili viste iniettate. Non va bene ...

  2. metodo di iniezione-"Una funzione così annotato viene eseguita automaticamente dopo il costruttore è stato eseguito" (GWT in Action, 2nd Ed.) Bene, "dopo che il ctor è stato eseguito" non è apparentemente abbastanza veloce perché la vista (o un servizio RPC iniettato in questo modo) non è ancora inizializzata quando viene chiamato il metodo start() di Activity e io ottenere un NPE.

  3. costruzione dell'iniettore con GWT.create nel campo di attività. Inutile, poiché non sarebbero più single.

risposta

7

Ciò che ha funzionato meglio per noi è stato l'utilizzo di Assisted Inject.

A seconda del caso, abbiamo definito le fabbriche di attività nell'attività stessa, in un pacchetto (per la creazione di tutte le attività in quel pacchetto) o in ActivityMapper.

public class MyActivity extends AbstractActivity { 
    private final MyView view; 

    @Inject 
    MyActivity(MyView view, @Assisted MyPlace place) { 
     this.view = view; 
     ... 
    } 
    ... 
} 

public class MyActivityMapper implements ActivityMapper { 
    public interface Factory { 
    MyActivity my(MyPlace place); 

    FooActivity foo(FooPlace place); 

    ... 
    } 

    // using field injection here, feel free to replace by constructor injection 
    @Inject 
    private Factory factory; 

    @Overrides 
    public Activity getActivity(Place place) { 
     if (place instance MyPlace) { 
     return factory.my((MyPlace) place); 
     } else if (place instance FooPlace) { 
     return factory.foo((FooPlace) place); 
     } 
     ... 
    } 
} 

// in the GinModule: 
install(new GinFactoryModuleBuilder().build(MyActivityMapper.Factory.class)); 

BTW, per il metodo di iniezione per lavorare, si deve ancora creare le vostre attività tramite GIN, in modo da dovreste avere gli stessi problemi con l'iniezione del costruttore. Non c'è magia, GIN non magicamente inietterà classi di cui non sa nulla e nemmeno sa quando sono state istanziate. È possibile attivare il metodo di iniezione in modo esplicito con l'aggiunta di metodi per la vostra Ginjector, ma io non lo consiglio (il codice dipenderebbe dal Ginjector, che è qualcosa che si dovrebbe evitare, se possibile):

interface MyGinjector extends Ginjector { 
    // This will construct a Foo instance and inject its constructors, fields and methods 
    Foo foo(); 

    // This will inject methods and (non-final) fields of an existing Bar instance 
    void whatever(Bar bar); 
} 

... 

Bar bar = new Bar("some", "arguments"); 
myGinjector.whatever(bar); 
... 

Un'ultima parola: non passerei l'oggetto posto direttamente all'attività. Cerca di disaccoppiare luoghi e attività, che ti consentano di muoverti (ad esempio, costruisci una versione mobile o tablet, in cui passi tra viste master e dettagli, invece di visualizzarle fianco a fianco) semplicemente cambiando il layout della "shell" e mappatori di attività. Per disaccoppiarli davvero, devi creare una specie di navigatore , per esempio,, che astragga le tue chiamate placeController.goTo(), in modo che le tue attività non abbiano mai a che fare con i luoghi.

+1

Ciao Thomas, Questo è esattamente ciò che facciamo nella nostra app (usando la fabbrica) e funziona bene. Tuttavia, come suggeriresti di integrarlo con AsyncProvider di GIN per la suddivisione del codice? (stiamo usando ActivityAsyncProxy http://ars-codia.raphaelbauer.com/2011/04/gwt-gin-and-simple-split-points.html) –

2

Nella mia esperienza una buona pratica è quella di disporre di mappatori di attività separati per gestire i luoghi e le attività (la mappatura). Nell'attività si ha la presentatrice, ecco esempio di attività:

public class ActivityOne extends AbstractActivity { 

    @Inject 
    private Presenter presenter; 

    @Override 
    public void start(AcceptsOneWidget panel, EventBus eventBus) { 
    presenter.go(panel); 
    } 

} 

Il presentatore hanno la vista iniettato all'interno, è costruito (presentatore) quando "go" metodo viene chiamato. Il presentatore è dichiarato come singleton nel modulo GIN e le viste sono in genere singleton (con alcune eccezioni come piccoli widget che appaiono in molti posti).

L'idea è spostare il contatto con la vista all'interno del presentatore (poiché l'obiettivo del relatore è quello di gestire la logica e recuperare/aggiornare i dati da/per la vista, in base a MVP). All'interno del presentatore si avrà anche i RPC servizi, non c'è bisogno di dichiarare perché GIN sarà "magicamente" fare istanza per voi, chiamando GWT.create Ecco un esempio di una semplice presentatore:

public class PresenterOneImpl implements Presenter { 

     @Inject 
     private MyView view; 


     @Inject 
     private SomeRpcServiceAsync someRpc; 


     @Override 
     public void go(AcceptsOneWidget panel) { 
     view.setPresenter(this); 
     panel.setWidget(view); 
     updateTheViewWithData(); 
     } 
} 

Alla fine devo notare che ci sono alcune attività, come quella del menu, che trattano direttamente i luoghi e la vista per visualizzare lo stato corrente. Queste attività sono memorizzate nella cache all'interno del programma di mappatura per evitare nuove istanze ogni volta che viene modificato il luogo.

3

Ho scelto un metodo leggermente diverso che ha tutta la flessibilità necessaria. Non ricordo dove ho scelto questo disegno, ma non è stata una mia idea. Creo l'attività in quanto tale

public class MyActivity extends AbstractActivity{ 

    private MyView view; 
    @Inject static PlaceController pc; 


    @Inject 
    public MyActivity(MyView view) { 
     super(); 
     this.view = view; 
    } 

    public MyActivity withPlace(MyPlace myPlace) { 
     return this; 
    } 
... 
} 

Poi io uso questo nel mapper un'attività come questa:

public class MyMapper implements ActivityMapper { 

    @Inject Provider<MyActivity> myActivityProvider; 

    public Activity getActivity(Place place) { 

     if (place instanceof MyPlace){ 
      return myActivityProvider.get().withPlace(place); 
     } else if 
... 

Assicurarsi inoltre che la vista è dichiarato Singleton nel file modulo di gin.