私はしばらくの間dagger2を使用しています。そして、アクティビティ/フラグメントごとに独自のコンポーネント/モジュールを作成するかどうか混乱しました。これを明確にするのを手伝ってください:
たとえば、アプリがあり、そのアプリには約50の画面があります。MVPパターンとDagger2forDIに従ってコードを実装します。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, ....) }
彼の説明は次のとおりです。アクティビティごとにコンポーネントやモジュールを作成する必要はありません。 友達の考えは全然良くないと思いますが、間違っていたら訂正してください。理由は次のとおりです。
多くのメモリリーク:
- ユーザーが開いているアクティビティが2つしかない場合でも、アプリは50人のプレゼンターを作成します。
- ユーザーがアクティビティを閉じた後も、そのプレゼンターは残ります
1つのアクティビティの2つのインスタンスを作成したい場合はどうなりますか?(どうすれば2人のプレゼンターを作成できますか)
アプリの初期化には多くの時間がかかります(多くのプレゼンター、オブジェクトなどを作成する必要があるため)
長い投稿で申し訳ありませんが、私と私の友人のためにこれを明確にするのを手伝ってください、私は彼を説得することはできません。 あなたのコメントは非常に高く評価されます。
/ ------------------------------------------------- ---------------------- /
デモを行った後に編集します。
まず、@ pandawarriorの回答に感謝します。この質問をする前に、デモを作成する必要がありました。ここでの私の結論が他の誰かを助けることができることを願っています。
- 私の友人が行ったことは、彼が提供メソッドにスコープを設定しない限り、メモリリークを引き起こしません。(たとえば、@ Singleton、または@UserScope、...)
- Providesメソッドにスコープがない場合は、多くのプレゼンターを作成できます。(それで、私の2番目のポイントも間違っています)
- Daggerは、必要な場合にのみプレゼンターを作成します。(したがって、アプリの初期化に長い時間はかかりません。レイジーインジェクションに混乱しました)
だから、私が上で言ったすべての理由はほとんど間違っています。しかし、それは2つの理由から、私の友人の考えに従う必要があるという意味ではありません。
彼がモジュール/コンポーネントですべてのプレゼンターを初期化するとき、それはソースのアーキテクチャーにとって良くありません。(これは、インターフェイス分離の原則に違反します。おそらく単一責任の原則にも違反します)。
スコープコンポーネントを作成すると、いつ作成され、いつ破棄されたかがわかります。これは、メモリリークを回避するための大きなメリットです。したがって、アクティビティごとに、@ ActivityScopeを使用してコンポーネントを作成する必要があります。私の友人の実装で、プロバイダーにスコープを入れるのを忘れたと想像してみましょう-メソッド=>メモリリークが発生します。
私の意見では、小さなアプリ(多くの依存関係がない、または同様の依存関係があるほんの数画面)で、友達のアイデアを適用できますが、もちろんお勧めしません。
詳細を読むことをお勧めします: Dagger 2のコンポーネント(オブジェクトグラフ)のライフサイクルを決定するものは何ですか? Dagger2アクティビティスコープ、いくつのモジュール/コンポーネントが必要ですか?
そしてもう1つの注意:オブジェクトがいつ破棄されるかを確認したい場合は、メソッドのオブジェクトを一緒に呼び出すことができ、GCはすぐに実行されます。
System.runFinalization();
System.gc();
これらのメソッドの1つだけを使用すると、GCが後で実行され、間違った結果が得られる可能性があります。
ControllerModule
されたものが新しいものを作成しPresenter
、プレゼンターがActivity
またはに挿入されFragment
ます。これに賛成または反対の確固たる意見はありますか?