Bir süredir dagger2 ile çalışıyorum. Ve her bir Etkinlik / Parça için kendi bileşenini / modülünü yaratırken kafam karıştı. Lütfen bunu açıklamama yardım et:
Örneğin, bir uygulamamız var ve uygulamanın yaklaşık 50 ekranı var. MVP modelini ve DI için Dagger2'yi izleyen kodu uygulayacağız. 50 etkinliğimiz ve 50 sunumcumuz olduğunu varsayalım.
Bence kodu genellikle şu şekilde düzenlemeliyiz:
Uygulama açıkken kullanılacak tüm nesneleri sağlayacak bir AppComponent ve AppModule oluşturun.
@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, ....) }
ActivityScope Oluşturun:
@Scope @Documented @Retention(value=RUNTIME) public @interface ActivityScope { }
Her Aktivite için Bileşen ve Modül oluşturun. Genellikle bunları Activity sınıfına statik sınıflar olarak koyarım:
@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.
Bunlar, bunu nasıl uygulayacağımı gösteren çok basit örnekler.
Ama bir arkadaşım bana başka bir uygulama verdi:
Tüm sunucuları sağlayacak PresenterModule oluşturun:
@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. }
AppModule ve AppComponent oluşturun:
@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, ....) }
Onun açıklaması şudur: Her aktivite için bileşenler ve modüller oluşturmak zorunda değildir. Arkadaşlarımın fikrinin kesinlikle hiç iyi olmadığını düşünüyorum, ama lütfen yanılıyorsam beni düzeltin. İşte nedenleri:
Çok fazla bellek sızıntısı :
- Uygulama, kullanıcının yalnızca 2 Etkinliği açık olsa bile 50 sunucu oluşturacaktır.
- Kullanıcı bir Aktiviteyi kapattıktan sonra, sunum yapan kişi kalmaya devam edecektir.
Bir Aktivitenin iki örneğini oluşturmak istersem ne olur? (nasıl iki sunucu yaratabilir)
Uygulamanın başlaması çok zaman alacak (çünkü birçok sunucu, nesne, ... oluşturması gerekiyor)
Uzun bir gönderi için özür dilerim, ama lütfen bunu kendim ve arkadaşım için açıklamama yardım edin, onu ikna edemiyorum. Yorumlarınız çok takdir edilecektir.
/ ------------------------------------------------- ---------------------- /
Demo yaptıktan sonra düzenleyin.
Öncelikle, @pandawarrior cevabı için teşekkürler. Bu soruyu sormadan önce bir Demo oluşturmalıydım. Umarım buradaki sonucum başka birine yardımcı olabilir.
- Arkadaşımın yaptığı şey, Provides yöntemlerine herhangi bir Kapsam koymadıkça bellek sızıntılarına neden olmaz. (Örneğin @Singleton veya @UserScope, ...)
- Provides yönteminin herhangi bir Kapsamı yoksa, birçok sunucu oluşturabiliriz. (Yani ikinci noktam da yanlış)
- Dagger, sunucuları yalnızca ihtiyaç duyulduğunda yaratacaktır. (Yani, uygulamanın başlaması uzun sürmeyecek, Lazy Injection ile kafam karıştı)
Yani yukarıda söylediğim tüm nedenler çoğunlukla yanlış. Ancak bu, iki nedenden ötürü arkadaşımın fikrini takip etmemiz gerektiği anlamına gelmez:
Tüm sunucuları modül / bileşene dahil ettiğinde, kaynağın mimarisi için iyi değildir. ( Arayüz ayrımı ilkesini , belki de Tek Sorumluluk ilkesini de ihlal ediyor ).
Bir Kapsam Bileşeni oluşturduğumuzda, ne zaman oluşturulduğunu ve ne zaman yok edildiğini bileceğiz, bu da bellek sızıntılarını önlemek için büyük bir avantajdır. Bu nedenle, her Aktivite için @ActivityScope ile bir Bileşen oluşturmalıyız. Arkadaşlarımın uygulamasıyla, Provider-method => 'a bir Scope koymayı unuttuğumuzu hayal edelim => bellek sızıntıları olacak.
Benim fikrime göre, küçük bir uygulama ile (çok sayıda bağımlılığı olmayan veya benzer bağımlılıkları olan sadece birkaç ekran) arkadaşlarımın fikrini uygulayabiliriz, ancak elbette tavsiye edilmiyor.
Daha fazlasını okumayı tercih edin: Dagger 2'de bir bileşenin (nesne grafiği) yaşam döngüsünü ne belirler? Dagger2 etkinlik kapsamı, kaç modüle / bileşene ihtiyacım var?
Ve bir not daha: Nesnenin ne zaman yok edildiğini görmek istiyorsanız, yönteminkileri birlikte çağırabilirsiniz ve GC hemen çalışacaktır:
System.runFinalization();
System.gc();
Bu yöntemlerden yalnızca birini kullanırsanız, GC daha sonra çalışır ve yanlış sonuçlar alabilirsiniz.
ControllerModule
will create a newPresenter
and then the presenter is injected in theActivity
orFragment
. Any solid opinion in favor or against this?