Я деякий час працюю з dagger2. І я заплутався у тому, щоб створити власний компонент / модуль для кожної діяльності / фрагмента. Будь ласка, допоможіть мені пояснити це:
Наприклад, у нас є програма, і вона має близько 50 екранів. Ми реалізуємо код за шаблоном MVP та Dagger2 для DI. Припустимо, у нас є 50 заходів та 50 ведучих.
На мою думку, зазвичай нам слід організувати код так:
Створіть AppComponent та AppModule, які забезпечать усі об’єкти, які будуть використовуватися під час роботи програми.
@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:
@Scope @Documented @Retention(value=RUNTIME) public @interface ActivityScope { }
Створіть компонент і модуль для кожної діяльності. Зазвичай я розміщую їх як статичні класи в класі 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.
Це просто дуже прості приклади, щоб показати, як я це реалізую.
Але мій друг просто дав мені ще одну реалізацію:
Створіть PresenterModule, який забезпечить усіх доповідачів:
@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 та 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, ....) }
Його пояснення полягає в тому, що йому не потрібно створювати компоненти та модулі для кожного виду діяльності. Я думаю, що ідея моїх друзів абсолютно не гарна, але, будь ласка, виправте мене, якщо я помиляюся. Ось причини:
Багато витоків пам'яті :
- Додаток створить 50 ведучих, навіть якщо у користувача відкрито лише 2 дії.
- Після закриття користувача активністю його ведучий все одно залишатиметься
Що станеться, якщо я хочу створити два екземпляри одного Діяльності? (як він може створити двох ведучих)
На ініціалізацію програми знадобиться багато часу (оскільки вона повинна створити багато презентаторів, об’єктів, ...)
Вибачте за довгий пост, але, будь ласка, допоможіть мені пояснити це мені та моєму другові, я не можу переконати його. Ваші коментарі будуть дуже вдячні.
/ ------------------------------------------------- ---------------------- /
Редагувати після демонстрації.
По-перше, дякую за відповідь @pandawarrior. Я повинен був створити демонстраційну програму, перш ніж задати це запитання. Сподіваюсь, мій висновок тут може допомогти комусь іншому.
- Те, що зробив мій друг, не спричиняє витоків пам’яті, якщо він не додає жодних областей застосування до методів Provides. (Наприклад, @Singleton, або @UserScope, ...)
- Ми можемо створити багато доповідачів, якщо метод Provides не має жодної сфери дії. (Отже, моя друга думка теж невірна)
- Dagger створюватиме ведучих лише тоді, коли вони потрібні. (Отже, програма не займе багато часу для ініціалізації, мене спантеличила Ледача ін’єкція)
Отже, усі причини, про які я говорив вище, здебільшого помилкові. Але це не означає, що нам слід наслідувати ідею мого друга з двох причин:
Це не добре для архітектури джерела, коли він запускає всіх доповідачів у модулі / компоненті. (Це порушує принцип розділення інтерфейсу , можливо , також принцип єдиної відповідальності ).
Коли ми створюємо компонент Scope, ми будемо знати, коли він створений і коли він знищений, що є величезною перевагою для уникнення витоків пам'яті. Отже, для кожної діяльності ми повинні створити Компонент із @ActivityScope. Давайте уявимо, з реалізацією моїх друзів, що ми забули ввести деякий обсяг у метод Provider => відбуватимуться витоки пам'яті.
На мій погляд, за допомогою невеликого додатка (лише декілька екранів без великої кількості залежностей або з подібними залежностями) ми могли б застосувати ідею моїх друзів, але, звичайно, це не рекомендується.
Краще читайте далі: Що визначає життєвий цикл компонента (графік об’єктів) у Dagger 2? Сфера діяльності Dagger2, скільки модулів / компонентів мені потрібно?
І ще одне зауваження: якщо ви хочете побачити, коли об’єкт буде знищений, ви можете викликати методи методу, і GC запуститься негайно:
System.runFinalization();
System.gc();
Якщо ви використовуєте лише один із цих методів, GC почне працювати пізніше, і ви можете отримати неправильні результати.
ControllerModule
створить новий,Presenter
а потім ведучий вводиться вActivity
абоFragment
. Будь-яка тверда думка на користь чи проти цього?