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