私はDagger2を自分のAndroidプロジェクトにセットアップする作業をしています。このフレームワークを使用するのは初めてで、これまでのところすべてがうまくいっています。しかし、できる方法でさまざまなアプローチが見られます。プロジェクトでこのフレームワークを設定します。両方を比較すると、どちらが優れているのでしょうか。結果は同じです。
私はこのガイドに従いました: https://github.com/codepath/Android_guides/wiki/Dependency-Injection-with-Dagger-2
インターネットで検索する場合は、すべてこのアプローチを使用します。 @Moduleと@Componentを使用して依存関係を定義します。
そして、アプリケーションは次のようになります。
public class MyApp extends Application {
private NetComponent mNetComponent;
@Override
public void onCreate() {
super.onCreate();
// Dagger%COMPONENT_NAME%
mNetComponent = DaggerNetComponent.builder()
// list of modules that are part of this component need to be created here too
.appModule(new AppModule(this)) // This also corresponds to the name of your module: %component_name%Module
.netModule(new NetModule("https://api.github.com"))
.build();
// If a Dagger 2 component does not have any constructor arguments for any of its modules,
// then we can use .create() as a shortcut instead:
// mNetComponent = com.codepath.dagger.components.DaggerNetComponent.create();
}
public NetComponent getNetComponent() {
return mNetComponent;
}
}
しかし、私は別の方法を見つけました(私はそれをテストしていません): https://google.github.io/dagger/Android.html そして、異なるクラスと注釈を使用して、それは完全に異なっているように見えます。次のようなものを使用します。
@Subcomponent(modules = ...)
public interface YourActivitySubcomponent extends AndroidInjector<YourActivity> {
@Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<YourActivity> {}
}
@Module(subcomponents = YourActivitySubcomponent.class)
abstract class YourActivityModule {
@Binds
@IntoMap
@ActivityKey(YourActivity.class)
abstract AndroidInjector.Factory<? extends Activity>
bindYourActivityInjectorFactory(YourActivitySubcomponent.Builder builder);
}
@Component(modules = {..., YourActivityModule.class})
interface YourApplicationComponent {}
public class YourApplication extends Application implements HasDispatchingActivityInjector {
@Inject DispatchingAndroidInjector<Activity> dispatchingActivityInjector;
@Override
public void onCreate() {
super.onCreate();
DaggerYourApplicationComponent.create()
.inject(this);
}
@Override
public DispatchingAndroidInjector<Activity> activityInjector() {
return dispatchingActivityInjector;
}
}
だから、私の質問は次のとおりです。
どちらの方がよいですか?
他のアプローチの代わりに1つのアプローチを選択する理由は何ですか?
Android現在公式に規定されている Dagger 2ドキュメント のDagger 2を設定する方法には、いくつかの利点があり、推奨されるはずです。利点は、詳細に説明されているものだけです。そこに、すなわち:
コードをコピーして貼り付けると、後でリファクタリングするのが難しくなります。そのブロックをコピーして貼り付ける開発者が増えるにつれて、実際に何をするのかを知る開発者は少なくなります。
より基本的には、インジェクターについて知るために、インジェクションを要求するタイプ(FrombulationActivity)が必要です。これが具象型ではなくインターフェースを介して行われたとしても、依存性注入のコア原則に違反します。クラスは、それがどのように注入されるかについて何も知らないはずです。
これらの理由を最初の例に適用してみましょう。
理由1
NetComponent
を使用したいアクティビティがあるとします。それをNetActivity
と呼びましょう。そのNetActivity
のonCreate(Bundle savedInstanceState)
メソッドは次のようになります。
_protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((MyApp) getApplicationContext()).getNetComponent().inject(this);
}
_
このコードは、オートミール(私の直喩ではない)に散らばっている足の爪の切り抜きの視覚的な魅力をすべて備えており、NetComponent
を使用するすべての注射部位のアクティビティにコピー貼り付けされます。ドキュメントのこの例のように、より複雑なコンポーネントを使用する場合:
_@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// DO THIS FIRST. Otherwise frombulator might be null!
((SomeApplicationBaseType) getContext().getApplicationContext())
.getApplicationComponent()
.newActivityComponentBuilder()
.activity(this)
.build()
.inject(this);
// ... now you can write the exciting code
_
}
さらに悪いことに。それは、注射部位全体にコピーして貼り付ける必要がある魔法のコードに簡単に縮退する可能性があります。変更された場合、1つのサイトだけを更新することを忘れて、アプリがクラッシュするのは簡単です。
理由2
依存性注入の大きな利点の1つは、依存性が依存性を知らない、または気にしないのと同じように、注入サイトがインジェクターを知らない、または気にする必要がないことです。 our NetActivity
に戻るには、次のようにします。
_((MyApp) getApplicationContext()).getNetComponent().inject(this);
_
アクティビティはそのインジェクター(NetComponent
)について「認識」しており、アクティビティはコンクリーションMyApp
および同じメソッドgetNetComponent()
と結合されています。これらのクラスのいずれかが変更された場合、NetActivity
も変更する必要があります。
Daggerバージョン2.10以降で利用可能なActivityand Fragments内の新しい注入方法に従うことの利点は、これらの欠点の正反対です。
さらに、 このブログ で指摘されているように、依存コンポーネントよりもサブコンポーネントを優先すると、アプリのメソッド数が減少します。
サブコンポーネントの使用は最初は難しいように思われるかもしれませんが、いくつかの明らかな利点があります。ただし、Daggerに依存するコンポーネントを学習するために、最初は理解しやすい場合があります。 2番目の例が最初は複雑すぎる場合は、フィネスを取得したときに推奨される方法に進むことができます。