Я работал с 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 нет области действия. (Итак, мой второй пункт тоже неверен)
- Кинжал будет создавать докладчиков только тогда, когда они необходимы. (Итак, приложение не займет много времени для инициализации, я был смущен Lazy Injection)
Итак, все причины, о которых я говорил выше, в основном неверны. Но это не значит, что мы должны следовать идее моего друга по двум причинам:
-
Это не хорошо для исходной архитектуры, когда он помещает всех докладчиков в модуль/компонент. (Это нарушает принцип сегрегации интерфейса, возможно, принцип единой ответственности).
-
Когда мы создаем компонент Scope, мы узнаем, когда он был создан, а когда уничтожен, что является огромным преимуществом для предотвращения утечек памяти. Таким образом, для каждого действия мы должны создать компонент с @ActivityScope. Давайте представим, с реализацией моих друзей, что мы забыли поместить Scope в Provider-method => утечки памяти.
По моему мнению, с небольшим приложением (всего несколько экранов без многих зависимостей или с аналогичными зависимостями) мы могли бы применить идею моих друзей, но, конечно, это не рекомендуется.
Предпочитаете читать дальше: Что определяет жизненный цикл компонента (граф объектов) в Dagger 2? Сфера деятельности Dagger2, сколько модулей/компонентов мне нужно?
И еще одно замечание: если вы хотите увидеть, когда объект уничтожен, вы можете вызвать те из методов вместе, и сборщик мусора немедленно запустится:
System.runFinalization();
System.gc();
Если вы используете только один из этих методов, GC запустится позже, и вы можете получить неправильные результаты.