Lavoro con dagger2 da un po '. E mi sono confuso se creare un proprio componente / modulo per ogni attività / frammento. Per favore aiutami a chiarire questo:
Ad esempio, abbiamo un'app e l'app ha circa 50 schermate. Implementeremo il codice seguendo il pattern MVP e Dagger2 per DI. Supponiamo di avere 50 attività e 50 presentatori.
Secondo me, di solito dovremmo organizzare il codice in questo modo:
Crea un AppComponent e un AppModule che forniranno tutti gli oggetti che verranno usati mentre l'app è aperta.
@Module public class AppModule { private final MyApplicationClass application; public AppModule(MyApplicationClass application) { this.application = application; } @Provides @Singleton Context provideApplicationContext() { return this.application; } //... and many other providers } @Singleton @Component( modules = { AppModule.class } ) public interface AppComponent { Context getAppContext(); Activity1Component plus(Activity1Module module); Activity2Component plus(Activity2Module module); //... plus 48 methods for 48 other activities. Suppose that we don't have any other Scope (like UserScope after user login, ....) }
Crea attività
@Scope @Documented @Retention(value=RUNTIME) public @interface ActivityScope { }
Crea componente e modulo per ogni attività. Di solito le inserisco come classi statiche all'interno della classe Activity:
@Module public class Activity1Module { public LoginModule() { } @Provides @ActivityScope Activity1Presenter provideActivity1Presenter(Context context, /*...some other params*/){ return new Activity1PresenterImpl(context, /*...some other params*/); } } @ActivityScope @Subcomponent( modules = { Activity1Module.class } ) public interface Activity1Component { void inject(Activity1 activity); // inject Presenter to the Activity } // .... Same with 49 remaining modules and components.
Questi sono solo esempi molto semplici per mostrare come lo implementerei.
Ma un mio amico mi ha appena dato un'altra implementazione:
Crea PresenterModule che fornirà a tutti i relatori:
@Module public class AppPresenterModule { @Provides Activity1Presenter provideActivity1Presentor(Context context, /*...some other params*/){ return new Activity1PresenterImpl(context, /*...some other params*/); } @Provides Activity2Presenter provideActivity2Presentor(Context context, /*...some other params*/){ return new Activity2PresenterImpl(context, /*...some other params*/); } //... same with 48 other presenters. }
Crea AppModule e AppComponent:
@Module public class AppModule { private final MyApplicationClass application; public AppModule(MyApplicationClass application) { this.application = application; } @Provides @Singleton Context provideApplicationContext() { return this.application; } //... and many other provides } @Singleton @Component( modules = { AppModule.class, AppPresenterModule.class } ) public interface AppComponent { Context getAppContext(); public void inject(Activity1 activity); public void inject(Activity2 activity); //... and 48 other methods for 48 other activities. Suppose that we don't have any other Scope (like UserScope after user login, ....) }
La sua spiegazione è: non deve creare componenti e moduli per ogni attività. Penso che l'idea dei miei amici non sia assolutamente buona, ma per favore correggimi se sbaglio. Ecco i motivi:
Molte perdite di memoria :
- L'app creerà 50 relatori anche se l'utente ha solo 2 attività aperte.
- Dopo che l'utente chiude un'attività, il relatore rimarrà comunque
Cosa succede se voglio creare due istanze di un'attività? (come può creare due presentatori)
Ci vorrà molto tempo per l'inizializzazione dell'app (perché deve creare molti presentatori, oggetti, ...)
Scusa per il post lungo, ma per favore aiutami a chiarire questo per me e il mio amico, non riesco a convincerlo. I tuoi commenti saranno molto apprezzati.
/ ------------------------------------------------- ---------------------- /
Modifica dopo aver fatto una demo.
Innanzitutto, grazie per la risposta di @pandawarrior. Avrei dovuto creare una demo prima di porre questa domanda. Spero che la mia conclusione qui possa aiutare qualcun altro.
- Ciò che il mio amico ha fatto non causa perdite di memoria a meno che non inserisca uno Scope nei metodi Provides. (Ad esempio @Singleton o @UserScope, ...)
- Possiamo creare molti presentatori, se il metodo Provides non ha alcun ambito. (Quindi, anche il mio secondo punto è sbagliato)
- Dagger creerà i presentatori solo quando sono necessari. (Quindi, l'app non impiegherà molto tempo per inizializzarsi, sono stato confuso da Lazy Injection)
Quindi, tutte le ragioni che ho detto sopra sono per lo più sbagliate. Ma ciò non significa che dovremmo seguire l'idea del mio amico, per due motivi:
Non va bene per l'architettura della sorgente, quando inserisce tutti i presentatori in modulo / componente. (Viola il principio di segregazione dell'interfaccia , forse anche il principio di responsabilità unica ).
Quando creiamo un componente Scope, sapremo quando viene creato e quando viene distrutto, il che è un enorme vantaggio per evitare perdite di memoria. Quindi, per ogni attività dovremmo creare un componente con un @ActivityScope. Immaginiamo, con l'implementazione dei miei amici, di aver dimenticato di mettere un po 'di Scope nel metodo Provider => si verificheranno perdite di memoria.
Secondo me, con una piccola app (solo poche schermate senza molte dipendenze o con dipendenze simili), potremmo applicare l'idea dei miei amici, ma ovviamente non è consigliabile.
Preferisco leggere di più su: Cosa determina il ciclo di vita di un componente (grafico a oggetti) in Dagger 2? Ambito di attività di Dagger2, di quanti moduli / componenti ho bisogno?
E un'altra nota: se vuoi vedere quando l'oggetto viene distrutto, puoi chiamare quelli del metodo insieme e il GC verrà eseguito immediatamente:
System.runFinalization();
System.gc();
Se utilizzi solo uno di questi metodi, GC verrà eseguito in un secondo momento e potresti ottenere risultati errati.
ControllerModule
ne creerà uno nuovoPresenter
e quindi il presentatore verrà iniettato inActivity
oFragment
. Qualche opinione solida a favore o contro questo?