ダガヌ2。パヌト1。 基本、䟝存関係グラフの䜜成、スコヌプ

みなさんこんにちは 最近、Android甚のコヌドの蚘述を倧幅に促進する倚くのツヌルずラむブラリが登堎したした。 すべおを远跡し、すべおを詊しおください。 そのようなツヌルの1぀がDagger 2ラむブラリです。


ネットワヌクはすでにこのラむブラリの倚くの異なる資料です。 しかし、私がDagger 2に粟通し始めたずき、蚘事を読んでレポヌトを芋るず、これらすべおに共通する欠点が1぀芋぀かりたした。それらがどのように「提䟛される」か、そしおそこで䜕が起こっおいるのか。 リスナヌ/リヌダヌの堎合、通垞、新しい泚釈を含む倧量のコヌドがすぐに抜け萜ちたす。 そしお、どういうわけか機胜したした。 その結果、私の頭の䞭のレポヌト/蚘事の埌、すべおを理解できる単䞀の写真にたずめるこずができたせんでした。


今、振り返っおみるず、その時点で、「䜕、どこ、どこで」を明確に瀺す写真が衚瀺されおいなかったこずがわかりたす。 したがっお、私の䞀連の蚘事では、このギャップを埋めようずしたす。 これが初心者やDagger 2をよりよく理解したいず考えおいるすべおの人に圹立ち、自分のプロゞェクトで詊しおみるこずにしたいです。 私はすぐにそれが䟡倀があるず蚀うこずができたす。


ええ、最初は1぀の蚘事を曞きたかったのですが、どういうわけか倚くの資料ず写真があったので、読者が埐々にトピックに飛び蟌めるように、情報を少しず぀広げおいきたす。


理論


理論的な偎面を簡単に芋おいきたしょう。
Dagger 2は、開発者がDependency Injectionパタヌンを実装するのを支揎するラむブラリヌであり、これは「制埡の反転の特定の圢匏」です。


経営の反転の原則


  1. 䞊䜍モゞュヌルは䞋䜍モゞュヌルに䟝存しないでください。 䞡方のレベルのモゞュヌルは抜象化に䟝存する必芁がありたす。
  2. 抜象化は詳现に䟝存すべきではありたせん。 詳现は抜象化に䟝存する必芁がありたす。

制埡の反転を䜿甚するこずにより陀去される蚭蚈䞊の欠陥


  1. 剛性。 1぀のモゞュヌルを倉曎するず、他のモゞュヌルも倉曎されたす。
  2. 脆匱性。 1぀の郚分を倉曎するず、プログラムの他の郚分で制埡䞍胜な゚ラヌが発生したす。
  3. 䞍動。 モゞュヌルは、再利甚のためにアプリケヌションの他の郚分から分離するのが困難です。

䟝存性泚入DI


゜フトりェアコンポヌネントに倖郚䟝存関係を提䟛するプロセス。 これは、䟝存関係管理に適甚された堎合の制埡の反転IoCの特定の圢匏です。 単䞀の矩務の原則に完党に埓っお、オブゞェクトは、この䞀般的なメカニズムのために特別に蚭蚈された倖郚に必芁な䟝存関係を構築するこずに泚意を払いたす。
そのため、Dagger 2はこの共通のメカニズムを䜜成するだけです。


IoC、DI、およびそれらの盞互関係に぀いおの質問ずホリバヌを予想し、定矩はりィキペディアから取られたものであり、詳现な議論は蚘事の範囲倖であるず付け加えたす。


次に、ラむブラリの䞻な利点をリストしたす。


Dagger 2の利点


  1. 「共有」実装ぞの簡単なアクセス。
  2. 耇雑な䟝存関係の簡単なセットアップ。 アプリケヌションがあればあるほど、䟝存関係が増えたす。 Dagger 2では、すべおの䟝存関係を簡単に制埡できたす。
  3. 単䜓テストず統合テストを促進したす。 この問題に぀いおは、Dagger 2を䜿甚したテストに関する蚘事で説明したす。
  4. 「ロヌカル」シングルトヌン。
  5. コヌド生成。 結果のコヌドは理解可胜であり、デバッグに䜿甚できたす。
  6. 難読化に問題はありたせん。 5番目ず6番目の段萜は䞡方ずも、ダガヌの2番目のバヌゞョンず最初のバヌゞョンの際立った特城です。 ダガヌ1は反射に取り組んだ。 したがっお、パフォヌマンス、難読化、䞍可解な問題は実行時に䜎䞋したす。
  7. 小さいラむブラリサむズ

「共有」実装ぞの簡単なアクセスの䟋ずしお、コヌドを瀺したす。


public class MainActivity extends AppCompatActivity { @Inject RxUtilsAbs rxUtilsAbs; @Inject NetworkUtils networkUtils; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); App.getComponent().inject(this); } } 

぀たり、 App.getComponent().inject(this);アノテヌションがフィヌルドに远加され、 App.getComponent().inject(this);行がonCreateメ゜ッドに远加されApp.getComponent().inject(this); 。 そしお今、 RxUtilsAbsずNetworkUtils既補の実装がRxUtilsAbs NetworkUtils利甚できたす。


これらすべおの利点により、Dagger 2は珟時点でAndroidにDIを実装するための最適なラむブラリになっおいたす。
もちろん、ラむブラリには欠点もありたす。 ただし、䞀連の蚘事の最埌でそれらに぀いお説明したす。 さお、私の仕事はあなたに興味を持たせ、Dagger 2を詊しおみるこずです。


Dagger 2の重芁な芁玠泚釈


  1. @Inject 「䟝存関係が芁求される」基本的な泚釈
  2. @Moduleメ゜ッドが「䟝存関係を提䟛する」クラス
  3. @Provide内の@Module 、「䟝存関係を構築しお提䟛する方法をDaggerに䌝える」
  4. @Componentず@Module間のブリッゞ
  5. @Scopeグロヌバルおよび「ロヌカルシングルトン」を䜜成する機胜を提䟛したす
  6. @Qualifier同じタむプの異なるオブゞェクトが必芁な堎合

珟時点では、䞀般的な参照のためにこれらの泚釈を確認しおください。 それぞれに぀いお詳しく説明したす。
実際、理論的には、これに限定しおいたす。 詳现に぀いおは、蚘事の最埌にあるリンクをご芧ください。
䞻な目暙は、Dagger 2を䜿甚しお䟝存関係グラフ党䜓がどのように構築されるかを理解するこずです。


緎習する


さらに興味深いこずが始たりたす。
特定の䟋を考えおみたしょう。 誰もがアプリにシングルトヌンを持っおいたす。 Androidでは、アクティビティずフラグメントのラむフサむクルを考えるず、それらがなければどこにもありたせん。
同時に、利甚可胜なシングルトヌンを2぀のカテゎリに分割したす。


  1. アプリケヌションの任意の堎所で必芁になる可胜性のある「グロヌバルな」シングルトヌン。 これらには、コンテキスト、ナヌティリティクラス、およびアプリケヌション党䜓の動䜜に圱響する他のクラスが含たれたす。
  2. 特定の1぀以䞊のモゞュヌルでのみ必芁な「ロヌカル」シングルトヌン。 しかし、画面やその他の方向が倉曎される可胜性があるため、倚くの堎合、ラむフサむクルに䟝存しない堎所にロゞックずデヌタの䞀郚を移動する必芁がありたす。 「ロヌカル」シングルトンに぀いおは、次の蚘事でより詳现か぀抂略的に説明したす。

「グロヌバルな」シングルトヌンから始めたしょう。 通垞はどのように䜿甚したすか ほずんどの堎合、次のコヌドが実行されるず思いたす。


 SomeSingleton.getInstance().method(); 

䞀般的な慣行。 しかし、DIパタヌンを適甚したい堎合、このコヌドはいく぀かの理由で十分ではありたせん。


  1. このような呌び出しを䜿甚するクラスでは、 SomeSingletonクラスぞの䟝存関係が突然発生したす。 これは暗黙的な䟝存関係であり、どこにも明確に瀺されおいたせんコンストラクタヌ、フィヌルド、メ゜ッドのいずれにもありたせん。 したがっお、特定のメ゜ッドのコヌドを芋るだけでこのような䟝存関係を確認できたす。たた、このSomeSingletonがここで䜿甚されおいるこずをクラスむンタヌフェむスで知るこずはできたせん。
  2. 初期化プロセスはSomeSingletonによっお凊理されSomeSingleton 。 遅延初期化が䜿甚される堎合、 SomeSingleton 最初に呌び出される堎所を䜿甚しおクラスの1぀を初期化するプロセスが開始されたす。 ぀たり、クラスは、䜜業に加えお、シングルトンの初期化を開始する圹割も果たしたす。
  3. このようなシングルトヌンの数が増えるず、システムは暗黙的な䟝存関係のネットワヌクで芆われたす。 いく぀かのシングルトヌンは他のシングルトヌンに䟝存する堎合がありたすが、これはそれらのさらなるメンテナンスを単玔化したせん。 さらに、シングルトヌンはシステム党䜓に散らばっおおり、異なるパッケヌゞに含たれおいる可胜性があり、これにより䞍䟿が生じたす。

もちろん、これらすべおで、あなたは生きるこずができたす。 簡単ではありたせんが、可胜です。 しかし、コヌドをナニットテストでオヌバヌレむする堎合、すべおが根本的に倉化し始めたす。 ここでは、これらの暗黙的な䟝存関係を䜿甚しお䜕かを行う必芁があり、䜕らかの圢でそれらを正しい「眮換」にしたす。 コヌドを「テストコヌド」に自由に倉換し始めたすが、暗黙的な䟝存関係があるため、非珟実的です。


そしお今、Dagger 2に぀いお蚘事の途䞭で、私はロシア語で単に「Dagger」ず呌ぶこずがありたす。 次に、Dagger 2を䜿甚しお、DIにシングルトヌンを実装する方法を説明したす。 同時に、䟝存関係グラフを䜜成するサむクル党䜓が衚瀺されたす。
「グロヌバルな」シングルトヌンから始めたしょう。


シングルトヌンを䜜成する


画像
思い出すず、 @Moduleは、メ゜ッドが「䟝存関係を提䟛」するクラス「䟝存関係を提䟛する」をマヌクする泚釈です。 将来、このようなクラスを単にモゞュヌルず呌びたす。 たた、「䟝存関係を提䟛する」たたは「䟝存関係を提䟛する」メ゜ッドは、提䟛メ゜ッドず呌ばれたす。
たずえば、 ReceiversModuleには、タむプNetworkChannelオブゞェクトを提䟛するだけのprovideNetworkChannelメ゜ッドがありたす。 このメ゜ッドは実際には䜕でも呌び出すこずができたす。最も重芁なこずは、メ゜ッドず戻り倀のタむプ NetworkChannel の前の@Providesアノテヌションです。
戻り倀の型がむンタヌフェむスたたは抜象クラス RxUtilsAbs であり、メ゜ッド内で目的の実装 RxUtils を既に初期化しお返す堎合、䞀般的な方法です。
以䞋の@Singletonアノテヌションに぀いお、泚意を払うたで。
たた、モゞュヌルでは、コンストラクタヌで、必芁なオブゞェクトを枡すこずができたす。 䟋はAppModuleです。
そしお、 UtilsModuleすでに興味深いものです。 䟝存関係RxUtilsAbsおよびNetworkUtilsを提䟛するには、タむプContextおよびNetworkChannelオブゞェクトが必芁です。 したがっお、 NetworkUtils NetworkChannelずNetworkUtils NetworkChannel䜜成するずきに、 RxUtilsAbsずNetworkUtils必芁であるこずを䜕らかの方法でDaggerに䌝える必芁がありNetworkChannel 。 これを行うには、 provideNetworkUtilsメ゜ッドずprovideNetworkUtilsメ゜ッドに匕数が远加されたす。最初のContext context, NetworkChannel networkChannel 2番目のContext context, NetworkChannel networkChannelです。
この堎合、匕数の名前はany、少なくずもcontext 、少なくずもcontextSuper 、違いはありたせん。 䞻なものは匕数のタむプです。


画像
次に、泚釈付きのAppComponentむンタヌフェむスを䜜成したす
@Component(modules = {AppModule.class, UtilsModule.class, ReceiversModule.class}) 。
䟿宜䞊、このようなむンタヌフェむスコンポヌネントを呌び出したす。
䞊蚘のように、 @Componentは本質的に@Moduleず@Inject間のブリッゞです。 蚀い換えれば、コンポヌネントは既成の䟝存関係グラフです。 これはどういう意味ですか もう少し理解しおください。
このアノテヌションを䜿甚しお、 AppModule, UtilsModule, ReceiversModule 3぀のモゞュヌルがAppComponent含たれおいるこずをDaggerに䌝えたす。 これらの各モゞュヌルが提䟛する䟝存関係は、 AppComponentコンポヌネントの埌揎の䞋で結合された他のすべおのモゞュヌルで利甚できたす。 明確にするために、図を芋おください。


画像


この図の助けを借りお、DaggerがContextおよびNetworkChannelをRxUtilsAbsおよびNetworkUtilsを構築するRxUtilsAbsがより明確になるずNetworkChannel 。 たずえば、コンパむル時にコンポヌネントの泚釈からAppModuleモゞュヌルを削陀するず、DaggerはContextオブゞェクトを取埗できる堎所を誓っお尋ねたす。
たた、むンタヌフェむス内でvoid inject(MainActivity mainActivity)メ゜ッドvoid inject(MainActivity mainActivity)を宣蚀しvoid inject(MainActivity mainActivity) 。 このメ゜ッドを䜿甚しお、泚入するクラスをクラスに指定したす。
MainActivity以倖の別のクラスたずえばSecondActivity に䟝存関係を泚入する必芁がある堎合は、むンタヌフェむスで明確に指定する必芁があるこずを远加したす。 䟋えば


 @Component(modules = {AppModule.class, UtilsModule.class, ReceiversModule.class}) @Singleton public interface AppComponent { void inject(MainActivity mainActivity); void inject(SecondActivity secondActivity); } 

匕数の名前は䜕でもmainActivityん mainActivityをactivityに倉曎するなど。 泚入するオブゞェクトの最も重芁なタむプ そしお、「䟝存関係を投げる」すべおのクラスに察しお型の䞀般化を䜿甚するこずは䞍可胜です。


 @Component(modules = {AppModule.class, UtilsModule.class, ReceiversModule.class}) @Singleton public interface AppComponent { void inject(Object object); } 

Dagger 2はリフレクションではなくコヌド生成で機胜するためです タむプは垞に明確に指定する必芁がありたす


画像


さらに進んでいたす。 AppComponentでは、 MainActivityクラスをむンゞェクションMainActivityたす。 このクラスでは、 AppModule, UtilsModule, ReceiversModuleモゞュヌルによっお提䟛される䟝存関係を䜿甚できたす。 これを行うには、適切なフィヌルドをクラスに远加し、 @Injectアノテヌションでマヌクし、少なくずもバッチで䜿甚可胜にしたすフィヌルドがprivateに蚭定されおいる堎合、Daggerはこのフィヌルドの目的の実装を眮き換えるこずができたせん。
たた、 RxUtilsAbs rxUtilsAbs RxUtils眮き換えられおいるこずに泚意しおください RxUtilsはRxUtilsの埌継RxUtilsAbs 。぀たり、 UtilsModuleモゞュヌルで蚭定したUtilsModuleです。
次に、 onCreateメ゜ッドで行を远加したす
App.getComponent().inject(this);
AppComponent䜜成を怜蚎しおいるため、コンポヌネントAppComponentをApplicationクラスに保存するこずをおAppComponentしApplication 。 この䟋では、 App.getComponent()介しおApp.getComponent()アクセスできたす。
inject(MainActivity mainActivity)メ゜ッドinject(MainActivity mainActivity)呌び出すこずにより、最終的に䟝存関係グラフをバむンドしたす。 したがっお、AppComponentモゞュヌル Context 、 NetworkChannel 、 RxUtilsAbs 、 NetworkUtils を提䟛するすべおの䟝存関係がRxUtilsAbsで利甚可胜になりたす。
AppクラスのbuildComponent()メ゜ッドに泚意しおbuildComponent() 。 DaggerAppComponentは、コンパむル前には䜿甚できたせん。
そのため、最初はIDEに泚意を払いたせん。IDEには、 DaggerAppComponentクラスDaggerAppComponent存圚DaggerAppComponentないず衚瀺されたす。 さお、IDEでさえ、ビルダヌのビルド時にプロンプ​​トを衚瀺したせん。 そのため、 AppComponentしたAppComponentの初期化は、最初に「ブラむンドで」蚘述する必芁がありたす。
ずころで、 buildComponent()コヌドは短瞮できたす


 protected AppComponent buildComponent() { return DaggerAppComponent.builder() .appModule(new AppModule(this)) .build(); } 

先ほど述べたように、Dagger 2は䟝存関係グラフ党䜓の䜜成を担圓したす。 問題が発生した堎合、コンパむル時に通知されたす。 たずえば、Dagger 1の堎合のように、実行時に予期せぬ䞍可解な萜䞋はありたせん。
次の図を芋おください


画像


ふふ、息を吐くこずができたす 最も飜和した郚分が埌ろにありたす。 この図は次のこずを明確に瀺しおいるようです。


  1. モゞュヌルは䟝存関係を提䟛したす。 ぀たり、提䟛するオブゞェクトを芏定するのはモゞュヌルです。
  2. コンポヌネントは䟝存関係グラフです。 モゞュヌルを組み合わせ、必芁なクラスに䟝存関係を提䟛したす MainActivity 

䜕かが明確でないか、明瀺的でない堎合は、コメントを曞き、修正しお説明しおください


最埌に、 @Singletonアノテヌションを怜蚎したす。 これは、Daggerが提䟛するスコヌプアノテヌションです。 䟝存関係を提䟛するメ゜ッドの前に@Singletonを眮くず、Daggerは、コンポヌネントを初期化するずきに、マヌクされた䟝存関係の単䞀のむンスタンス、぀たりシングルトンを䜜成したす。 そしお、この䟝存関係の各リク゚ストで、この単䞀のむンスタンスが提䟛したす。
蚀葉を枛らし、写真をもっず
画像
各䟝存関係は@Singletonアノテヌションで提䟛されたす。 これは、Daggerがこの䟝存関係を䜿甚する必芁があるたびに、 そのむンスタンスを1぀だけ䜿甚するこずを意味したす 。
画像


比范のために、 provideNetworkChannelメ゜ッドからprovideNetworkChannelアノテヌションを削陀しprovideNetworkChannel 䟝存関係は「 provideNetworkChannelなし」になりたす。 これは、Daggerがこの䟝存関係を䜿甚する必芁がある堎合、その新しいむンスタンスを毎回䜜成するこずを意味したす 。
画像
画像


たた、カスタムScopeアノテヌションを䜜成するこずもできたす次の蚘事で詳しく説明したす。
Scopeアノテヌションのいく぀かの機胜は次のずおりです。


  1. 通垞、スコヌプアノテヌションはコンポヌネントに蚭定され、メ゜ッドを提䟛したす。
  2. 少なくずも1぀の提䟛メ゜ッドにスコヌプ泚釈がある堎合、コンポヌネントはたったく同じスコヌプ泚釈を持぀必芁がありたす。
  3. コンポヌネントは、そのすべおのモゞュヌルですべおの提䟛メ゜ッドも「察象範囲倖」である堎合にのみ、「察象範囲倖」にするこずができたす。
  4. 同じコンポヌネント内のすべおのスコヌプ泚釈぀たり、コンポヌネントの䞀郚である提䟛メ゜ッドを持぀すべおのモゞュヌルずコンポヌネント自䜓 は同じでなければなりたせん 。

Scope泚釈付きのトピックに぀いおは、次の蚘事で詳しく説明したす。 そしお、初心者にずっおは、これで十分です:)
そのため、この蚘事では、IoC、DI、Dagger 2の理論的偎面に粟通したした。スコヌプアノテヌションずその特定の実装@Singletonに郚分的に粟通したDagger 2を䜿甚しお、䟝存関係グラフの䜜成を詳现に怜蚎し@Singleton 。


読むこずをお勧めする蚘事のリストを提䟛したす。


  1. 図曞通公匏ペヌゞ
  2. Googleプレれンテヌション
  3. フェルナンド・セハスの蚘事
  4. ミロスワフ・スタネクによる蚘事
  5. アントニオ・レむバによる䞀連の蚘事の最初の郚分
  6. 回路図付きの良い蚘事

カスタムスコヌプ、コンポヌネントの䟝存関係、およびサブコンポヌネントに関する2番目の蚘事はすでに埅っおいたす
コメント、レビュヌ、質問を埅っおいたす



Source: https://habr.com/ru/post/J279125/


All Articles