コデむン。 基本

Kodeinが初めお目にする人向けのわかりやすいガむドは芋぀かりたせんでした。たた、ドキュメントはすべおの堎所で透過的で䞀貫性がないため、ラむブラリの䞻な機胜を共有したいず思いたす。 䞀郚のラむブラリ機胜がリリヌスされたすが、これは基本的に高床な郚分です。 ここにすべおがありたすので、蚘事を読んで、通垞通りに起動しお、 Kodein䟝存関係の実装を開始できたす。 Kodein 6.0.0はSupport Library 28たたはAndroidXを必芁ずし、倚くのサヌドパヌティラむブラリがただ互換性のあるバヌゞョンを提䟛しおいないため、誰も決しおそれらに切り替えないため、この蚘事はKodein 5.3.0に基づいおいたす。


Kodeinは、䟝存性泚入DIを実装するためのラむブラリです。 この抂念に慣れおいない堎合は、 Dagger2に関する蚘事の冒頭を読んでください。著者がDIの理論的な偎面を簡単に説明しおいたす。

この蚘事では、Androidの䟋を䜿甚しおすべおを怜蚎したすが、開発者によるず、KodeinはKotlinがサポヌトするすべおのプラットフォヌムJVM、Android、JS、Nativeで同じように動䜜したす。

蚭眮


Javaにはtype erasureがあるずいう事実により、問題が発生したす-コンパむラヌはゞェネリック型を消去したす。 バむトコヌドレベルでは、 List<String>およびList<Date>は単なるListです。 それでも、ゞェネリック型に぀いおの情報を取埗する方法は残っおいたすが、コストがかかり、JVMずAndroidでのみ機胜したす。 この点に関しお、 Kodein開発者は2぀の䟝存関係のいずれかを䜿甚するこずをお勧めしたす。1぀は䜜業䞭にゞェネリック型に関する情報を受け取り kodein-generic 、もう1぀は受け取らない kodein-erased  たずえば、 kodein-erased List<String>およびList<Date >を䜿甚する堎合はList<*>ずしお保存され、 kodein-genericを䜿甚する堎合はすべおが指定されたタむプずずもに、぀たりList<String>およびList<Date>ずしお保存されたすList<Date>それぞれ。

遞択方法

JVMの䞋ではなく曞き蟌みkodein-erased䜿甚したす。そうでない堎合は䞍可胜です。
JVMの䞋で曞くずパフォヌマンスの問題はあなたにずっお非垞に重芁ですkodein-erased䜿甚できたすが、泚意しおください、この経隓はこれらの蚀葉の悪い意味で予期しないかもしれたせん。 特別なパフォヌマンス芁件なしで通垞のアプリケヌションを䜜成する堎合は、 kodein-generic䜿甚したす。

最終的に、パフォヌマンスぞのDIの圱響に぀いお考える堎合、ほずんどの堎合、䟝存関係の倧郚分は䞀床䜜成されるか、䟝存関係は繰り返し再利甚するために䜜成されたすが、そのようなアクションを䜿甚するず、アプリケヌションのパフォヌマンスに倧きな圱響を䞎える可胜性は䜎くなりたす。

したがっお、むンストヌルしたす

たず-リポゞトリ内のbuild.gradleにjcenterがあるはずです存圚しない堎合。

 buildscript { repositories { jcenter() } } 

次に、䟝存関係ブロックで、䞊蚘の基本的な䟝存関係のいずれかを远加したす。

 implementation "org.kodein.di:kodein-di-generic-jvm:$version" 

 implementation "org.kodein.di:kodein-di-erased-jvm:$version" 

Androidに぀いお説明しおいるため、䟝存関係が増えたす。 もちろん、それなしでも実行できたす。Kodeinは正垞に機胜したすが、Androidに圹立぀远加機胜を拒吊する理由は䜕ですか蚘事の最埌で説明したす。 遞択はあなた次第ですが、远加するこずを提案したす。

ここにもオプションがありたす。

たず、 SupportLibraryを䜿甚しおいたせん

 implementation "org.kodein.di:kodein-di-framework-android-core:$version" 

2番目-䜿甚

 implementation "org.kodein.di:kodein-di-framework-android-support:$version" 

第䞉-あなたはAndroidXを䜿甚しおいたす

 implementation "org.kodein.di:kodein-di-framework-android-x:$version" 

䟝存関係の䜜成を開始したす


Dagger2を䜿甚しお、アプリケヌションの起動時に、Applicationクラスで䟝存関係を䜜成および初期化するこずに慣れおいたす。

Kodeinでは、これは次のように行われたす。

 class MyApp : Application() { val kodein = Kodein { /*  */ } } 

䟝存関係宣蚀は垞に次で始たりたす

 bind<TYPE>() with 

タグ


Kodein䟝存関係タグ付けは、機胜がDagger2 Qualifier䌌た機胜Dagger2 。 Dagger2 、個別のQualifierを実行するか、実際にはQualifierでもある@Named("someTag")䜿甚する必芁がありたす。 䞀番䞋の行は単玔です-このようにしお、同じタむプの2぀の䟝存関係を区別したす。 たずえば、状況に応じおアプリケヌションたたは特定のActivityのontextを取埗する必芁があるため、䟝存関係を宣蚀するずきにこのタグを指定する必芁がありたす。 Kodein䜿甚Kodeinず、タグなしで1぀の䟝存関係を宣蚀できKodein 。これはベヌス䟝存関係であり、䟝存関係の受信時にタグを指定しない堎合は取埗したす。他のタグはタグ付けする必芁があり、タグは䟝存関係の受信時に指定する必芁がありたす。

 val kodein = Kodein { bind<Context>() with ... bind<Context>(tag = "main_activity") with ... bind<Context>(tag = "sale_activity") with ... } 

tagパラメヌタの型はAnyであるため、単なる文字列以䞊のものを䜿甚できたす。 ただし、タグずしお䜿甚されるクラスは、 equals hashCodeずhashCodeメ゜ッドを実装する必芁equalsにhashCode 。 䟝存関係を䜜成するか受信するかにかかわらず、タグを名前付き匕数ずしお関数に枡す必芁が垞にありたす。

䟝存性泚入のタむプ


Kodeinに䟝存関係を提䟛する方法はいく぀かありたす。基本的なこずKodeinたす- Kodeinを䜜成したす。 シングルトンは、䜜成されたKodeinむンスタンスのフレヌムワヌク内にKodeinたす。

シングルトンの玹介


䟋から始めたしょう

 val kodein = Kodein { bind<IMyDatabase>() with singleton { RoomDb() } } 

したがっお、 IMyDatabaseを提䟛提䟛し、その背埌にRoomDbむンスタンスが隠されたす。 RoomDbのむンスタンスは、䟝存関係の最初のリク゚ストでKodeinれ、新しいKodeinむンスタンスがKodeinれるたでKodeinされたせん。 シングルトンは同期化されお䜜成されたすが、必芁に応じお非同期化するこずもできたす。 これにより生産性が向䞊したすが、それに䌎うリスクを理解する必芁がありたす。

 val kodein = Kodein { bind<IMyDatabase>() with singleton(sync = false) { RoomDb() } } 

䟝存関係のむンスタンスを最初の呌び出しではなく、 Kodeinむンスタンスの䜜成盎埌に䜜成するKodein堎合は、別の関数を䜿甚したす。

 val kodein = Kodein { bind<IMyDatabase>() with eagerSingleton { RoomDb() } } 

垞に䟝存関係の新しいむンスタンスを䜜成する


シングルトヌンではなく、䟝存関係にアクセスしおその新しいむンスタンスを取埗するずきに垞に䜜成するこずができたす。 これには、 provider関数が䜿甚されたす。

 val kodein = Kodein { bind<IMainPresenter>() with provider { QuantityPresenter() } } 

この堎合、 IMainPresenter䟝存関係を芁求するIMainPresenter 、 QuantityPresenter新しいむンスタンスが䜜成されたす。

垞に䟝存関係の新しいむンスタンスを䜜成し、パラメヌタヌを䟝存関係のコンストラクタヌに枡したす


前の䟋のように、䟝存関係のリク゚ストごずに新しいむンスタンスを取埗できたすが、同時に䟝存関係を䜜成するためのパラメヌタヌを指定したす。 パラメヌタヌは最倧5にするこずができたす。 この動䜜には、 factoryメ゜ッドを䜿甚したす。

 val kodein = Kodein { bind<IColorPicker>() with factory { r: Int, g: Int, b: Int, a: Int -> RgbColorPicker(r, g, b, a) } } 

パラメヌタに応じおキャッシュされたむンスタンスを䜜成するたびに


前の段萜を読んで、枡されるパラメヌタヌに埓っお毎回新しいむンスタンスを受け取るのではなく、同じパラメヌタヌの䟝存関係の同じむンスタンスを受け取るのが良いず思うかもしれたせん。

 val kodein = Kodein { bind<IRandomIntGenerator>() with multiton { from: Int, to: Int -> IntRandom(from, to) } } 

䞊蚘の䟋では、最初にパラメヌタヌ5ず10䟝存関係を取埗するずきに、 IntRandom(5, 10)新しいむンスタンスを䜜成したす。同じパラメヌタヌで䟝存関係を再床呌び出すず、以前に䜜成したむンスタンスを取埗したす。 したがっお、遅延初期化を䜿甚したシングルトヌンからのmapが刀明したす。 factoryの堎合のように、匕数factory最倧5です。

シングルトヌンず同様に、ここで同期をオフにできたす。

 val kodein = Kodein { bind<IRandomIntGenerator>() with multiton(sync = false) { from: Int, to: Int -> IntRandom(from, to) } } 

Kodeinで゜フトリンクず匱いリンクを䜿甚する


singletonたたはmultitonを䜿甚しお䟝存関係を提䟛する堎合、栌玍されたむンスタンスぞの参照のタむプを指定できたす。 䞊蚘で怜蚎した通垞の堎合-これは通垞のstrongリンクになりたす。 ただし、 softリンクずweakリンクを䜿甚するこずは可胜です。 これらの抂念に慣れおいない堎合は、 こちらをチェックしおください 。

したがっお、アプリケヌションラむフサむクルの䞀郚ずしおシングルトヌンが再䜜成される堎合ずそうでない堎合がありたす。

 val kodein = Kodein { bind<IMyMap>() with singleton(ref = softReference) { WorldMap() } bind<IClient>() with singleton(ref = weakReference) { id -> clientFromDB(id) } } 

ストリヌムごずに個別のシングルトン


これは同じシングルトンですが、䟝存関係を芁求する各スレッドに察しお、シングルトンが䜜成されたす。 これを行うには、䜿い慣れたパラメヌタヌref䜿甚したす。

 val kodein = Kodein { bind<Cache>() with singleton(ref = threadLocal) { LRUCache(16 * 1024) } } 

埋め蟌み可胜な䟝存関係ずしおの定数


定数を䟝存関係ずしお提䟛できたす。 このドキュメントでは、 Kodeinを䜿甚するず、プリミティブやデヌタクラスなど、継承やむンタヌフェむスのない単玔型の定数をKodein必芁があるずいう事実に泚目しおいたす。

 val kodein = Kodein { constant(tag = "maxThread") with 8 constant(tag = "serverURL") with "https://my.server.url" 

タむプを倉曎せずに䟝存関係を䜜成する


たずえば、䟝存関係をシングルトンずしお提䟛したいが、むンタヌフェむスの背埌に隠さないでください。 bindを呌び出しおwith代わりにfromを䜿甚bind堎合、単にタむプを指定するこずはできたせん。

 val kodein = Kodein { bind() from singleton { Gson() } 

䞊蚘の䟋の䟝存関係には、関数の戻り倀の型がありたす。぀たり、 Gson型の䟝存関係がGsonたす。

スヌパヌクラスたたはむンタヌフェヌスのサブタむプごずに䟝存関係を䜜成したす


Kodein䜿甚Kodeinず、単䞀のむンタヌフェヌスを実装する特定のクラス耇数Kodeinの子孫にさたざたな方法で䟝存関係を提䟛できKodein 。

 val kodein = Kodein { bind<Animal>().subTypes() with { animalType -> when (animalType.jvmType) { Dog::class.java -> eagerSingleton { Dog() } else -> provider { WildAnimal(animalType) } } } 

Animalクラスは、スヌパヌクラスたたはむンタヌフェむスのいずれかです.subtypesを䜿甚しお、 TypeToken<*> .subtypesを取埗したす。 animalTypeからJavaクラスを取埗し、それに応じお、さたざたな方法で䟝存関係を提䟛したす。 この機胜は、 TypeTokenたたはその掟生物を倚くの堎合のコンストラクタヌパラメヌタヌずしお䜿甚する堎合に圹立ちたす。 たた、この方法では、異なるタむプに察しお同じ䟝存関係を䜜成しお、䞍芁なコヌドを回避できたす。

パラメヌタヌずしお他の䟝存関係を必芁ずする䟝存関係を䜜成する


ほずんどの堎合、䟝存関係ずしおパラメヌタヌなしのクラスを䜜成するだけでなく、コンストラクタヌにパラメヌタヌを枡す必芁があるクラスを䜜成したす。

 class ProductGateway(private val api: IProductApi, private val dispatchers: IDispatchersContainer) : IProductGateway 

Kodein以前に䜜成された䟝存関係を持぀クラスを䜜成するKodein 、instance関数呌び出しをパラメヌタヌずしお枡すだけで十分です。 この堎合、䜜成の順序は重芁ではありたせん。

 bind<IDispatchersContainer>() with singleton { DispatchersContainer() } bind<IProductGateway>() with singleton { ProductGateway(instance(), instance()) } bind<IProductApi>() with singleton { ProductApi() } 

instance()代わりに、 provider()たたはfactory()呌び出しがある堎合がありたす。これらのメ゜ッドに぀いおは、䟝存関係の取埗ず実装に関するセクションで詳しく芋おいきたす。

以前に䜜成した䟝存関係メ゜ッドを呌び出しお䟝存関係を䜜成したす


あたり良く聞こえたせんが、 instance<TYPE>を呌び出しお、すでに提䟛されおいるクラスを取埗し、このクラスのメ゜ッドを呌び出しお新しい䟝存関係を取埗できたす。

 bind<DataSource>() with singleton { MySQLDataSource() } bind<Connection>() with provider { instance<DataSource>().openConnection() } 

モゞュヌル


Dagger2を䜿甚しDagger2䟝存関係をDagger2慣れおDagger2 。 Kodeinでは、䞀芋、すべおがあたり良く芋えたせん。 Applicationクラスで倚くの䟝存関係を䜜成する必芁がありたすが、個人的にはあたり奜きではありたせん。 しかし、解決策がありたすKodeinでは、モゞュヌルを䜜成し、必芁に応じおそれらの堎所に接続するこずもできたす。

  val appModule = Kodein.Module("app") { bind<Gson>() with singleton { provideGson() } bind<HttpClient>() with singleton { provideHttpClient() } } val kodein: Kodein = Kodein { import(appModule) bind<ISchedulersContainer>() with singleton { SchedulersContainer() } //   } 

ただし、モゞュヌルは䟝存関係を取埗するためのメ゜ッドを宣蚀する単なるコンテナであり、クラス自䜓は䜜成しないこずに泚意しおください。 したがっお、䟝存関係の受信をモゞュヌルでシングルトンずしお宣蚀し、このモゞュヌルをKodein 2぀の異なるむンスタンスにKodeinするず、 Kodeinむンスタンスごずに1぀ず぀、2぀の異なるシングレットが取埗されたす。

たた、各モゞュヌルの名前は䞀意である必芁がありたす。 ただし、モゞュヌルを別のプロゞェクトからむンポヌトする必芁がある堎合、名前の䞀意性を保蚌するのは困難です;このため、モゞュヌルの名前を倉曎するか、名前にプレフィックスを远加できたす。

 import(apiModule.copy(name = "firstAPI")) import(secondApiModule.copy(prefix = "secondAPI-")) 

私は、モゞュヌルが互いに䟝存し、ある皮の階局を構成しおいるずきに䜜業に慣れおいたす。 各モゞュヌルを䞀床Kodeinむンポヌトできるため、同じ䟝存モゞュヌルを持぀2぀のモゞュヌルを1぀のKodeinにむンポヌトしようずするず、アプリケヌションがクラッシュしたす。 解決策は簡単ですimportOnce(someModule)呌び出しを䜿甚しおむンポヌトする必芁がありたす。これは、同じ名前のモゞュヌルが以前にむンポヌトされたかどうかを確認し、必芁に応じおむンポヌトしたす。

たずえば、そのような堎合、アプリケヌションはクラッシュしたす。

  val appModule = Kodein.Module("app") { bind<Gson>() with singleton { provideGson() } } val secondModule = Kodein.Module("second") { import(appModule) } val thirdModule = Kodein.Module("third") { import(appModule) } val kodein: Kodein = Kodein { import(secondModule) import(thirdModule) } 

  val appModule = Kodein.Module("app") { bind<Gson>() with singleton { provideGson() } } val secondModule = Kodein.Module("second") { importOnce(appModule) } val thirdModule = Kodein.Module("third") { import(appModule) } val kodein: Kodein = Kodein { import(secondModule) import(thirdModule) } 

ただし、 importOnce呌び出しが2回目の接続詊行である堎合、すべおが機胜したす。 泚意しおください。

  val appModule = Kodein.Module("app") { bind<Gson>() with singleton { provideGson() } } val secondModule = Kodein.Module("second") { import(appModule) } val thirdModule = Kodein.Module("third") { importOnce(appModule) } val kodein: Kodein = Kodein { import(secondModule) import(thirdModule) } 

継承


同じモゞュヌルを2回䜿甚するず、異なる䟝存関係が䜜成されたすが、継承ずDagger2䌌た動䜜の実装に぀いおはDagger2でしょうか すべおが簡単ですKodeinむンスタンスから継承するだけで、盞続人の芪のすべおの䟝存関係にアクセスできたす。

 val kodein: Kodein = Kodein { bind<ISchedulersContainer>() with singleton { SchedulersContainer() } //   } val subKodein = Kodein { extend(kodein) //   } 

再定矩


デフォルトでは、䟝存関係をオヌバヌラむドするこずはできたせん。そうしないず、ナヌザヌが倢䞭になり、アプリケヌションが正しく動䜜しない理由を探したす。 ただし、 bind関数の远加パラメヌタヌを䜿甚しおこれを行うこずは可胜です。 この機胜は、たずえばテストの敎理に圹立ちたす。

 val kodein = Kodein { bind<Api>() with singleton { ApiImpl() } /* ... */ bind<Api>(overrides = true) with singleton { OtherApiImpl() } } 

既定では、モゞュヌルずその䟝存関係は、 Kodeinオブゞェクトで既に宣蚀されおいる䟝存関係をオヌバヌラむドできたせんが、モゞュヌルをむンポヌトするずきに、その䟝存関係を既存のものによっおオヌバヌラむドできるように指定できたす。このモゞュヌル内では、他のナヌザヌがオヌバヌラむドできる䟝存関係を既に指定できたす。

あたり明確に聞こえたせんが、䟋を䜿甚したしょう。 これらの堎合、アプリケヌションはクラッシュしたす。

  val appModule = Kodein.Module("app") { bind<Gson>() with singleton { provideGson() } } val kodein: Kodein = Kodein { bind<Gson>() with singleton { provideGson() } import(appModule) } 

  val appModule = Kodein.Module("app") { bind<Gson>() with singleton { provideGson() } } val kodein: Kodein = Kodein { bind<Gson>() with singleton { provideGson() } import(appModule, allowOverride = true) } 

そしお、これでは、モゞュヌルの䟝存関係がKodeinオブゞェクトで宣蚀された䟝存関係を䞊曞きしたす。

  val appModule = Kodein.Module("app") { bind<Gson>(overrides = true) with singleton { provideGson() } } val kodein: Kodein = Kodein { bind<Gson>() with singleton { provideGson() } import(appModule, allowOverride = true) } 

しかし、本圓にやりたいこずを理解しおいる堎合は、 Kodeinオブゞェクトず同じ䟝存関係がある堎合にそれらを再定矩し、アプリケヌションがクラッシュしないモゞュヌルを䜜成できたす。 モゞュヌルにはallowSilentOverrideパラメヌタヌを䜿甚したす。

 val testModule = Kodein.Module(name = "test", allowSilentOverride = true) { bind<EmailClient>() with singleton { MockEmailClient() } } 

ドキュメントでは、䟝存関係の継承ず再定矩、および継承者の䟝存関係のコピヌに関するより耇雑な状況に぀いお説明しおいたすが、これらの状況はここでは考慮したせん。

䟝存関係の取埗ず泚入


最埌に、倚くの方法で䟝存関係を宣蚀する方法を芋぀けたした。今床は、クラスで䟝存関係を取埗する方法を芋぀けたす。

Kodein開発者は、䟝存関係を取埗する2぀の方法- injectionずretievalたす。 芁するに、 injectionは、クラスが䜜成されたずき、぀たりコンストラクタヌですべおの䟝存関係を受け取るずきであり、 retrievalは、クラス自䜓がその䟝存関係を取埗する責任があるずきです。

injectionを䜿甚injection 、クラスはKodeinに぀いお䜕も認識せず、クラス内のコヌドはクリヌンですが、 Kodeinを䜿甚するず、䟝存関係をより柔軟に管理する機䌚がありたす。 retrievalの堎合、䟝存関係ぞの最初のアピヌルの時点でのみretrievalすべおの䟝存関係が遅延的に取埗されたす。

䟝存関係を䜿甚するためのKodeinメ゜ッド


Kodeinクラスのむンスタンスには、䟝存関係、䟝存関係ファクトリ、たたは䟝存関係プロバむダヌを返す3぀のメ゜ッドがありprovider() 。それぞれ、 instance() 、 factory()およびprovider()です。 したがっお、 factoryたたはproviderを䜿甚しお䟝存関係を提䟛するず、関数実行の結果だけでなく、関数自䜓も受け取るこずができたす。 すべおのバリ゚ヌションでタグを䜿甚できるこずに泚意しおください。

  val kodein: Kodein = Kodein { bind<BigDecimal>() with factory { value: String -> BigDecimal(value) } bind<Random>() with provider { Random() } } private val number: BigDecimal by instance(arg = "23.87") private val numberFactory: (value: String) -> BigDecimal by factory() private val random: Random by instance() private val randomProvider: () -> Random by provider() 

コンストラクタヌによる䟝存性泚入


すでに理解しおいるように、それはinjectionに関するものです。 実装するには、たずコンストラクタヌですべおのクラスの䟝存関係を取り出しおから、 kodein.newInstanceを呌び出しおクラスのむンスタンスを䜜成する必芁がありたす

 class ProductApi(private val client: HttpClient, private val gson: Gson) : IProductApi class Application : Application() { val kodein: Kodein = Kodein { bind<Gson>() with singleton { provideGson() } bind<HttpClient>() with singleton { provideHttpClient() } } private val productApi: IProductApi by kodein.newInstance { ProductApi(instance(), instance()) } } 

ヌル可胜プロパティぞの䟝存性泚入


䟝存関係が宣蚀されおいるかどうかわからない可胜性がありたす。 䟝存関係がKodeinむンスタンスで宣蚀されおいない堎合、䞊蚘の䟋のコヌドはKodein.NotFoundExceptionたす。 結果ずしおnull関数を取埗したい堎合、䟝存関係がない堎合、 instanceOrNull() 、 factoryOrNull()およびproviderOrNull() 3぀の補助関数がありproviderOrNull() 。

 class ProductApi(private val client: HttpClient?, private val gson: Gson) : IProductApi class Application : Application() { val kodein: Kodein = Kodein { bind<Gson>() with singleton { provideGson() } } private val productApi: IProductApi by kodein.newInstance { ProductApi(instanceOrNull(), instance()) } } 

クラス内の䟝存関係を取埗したす。


前述のように、 retrievalを䜿甚する堎合、すべおの䟝存関係の初期化はデフォルトで遅延したす。 これにより、必芁な堎合にのみ䟝存関係を取埗し、システムが䜜成するクラスの䟝存関係を取埗できたす。

Activity 、 Fragmentおよび独自のラむフサむクルを持぀他のクラスはすべおそれらに぀いおです。

Activity䟝存関係を実装するには、Kodeinのむンスタンスぞのリンクのみが必芁です。その埌、既知のメ゜ッドを䜿甚できたす。 実際、䞊蚘のretrieval䟋を芋おきたした。プロパティを宣蚀し、それを関数instance() 、 factory()たたはprovider()いずれかに委任するだけです。

 private val number: BigDecimal by kodein.instance(arg = "23.87") private val numberFactory: (value: String) -> BigDecimal by kodein.factory() private val random: Random? by kodein.instanceOrNull() private val randomProvider: (() -> Random)? by kodein.providerOrNull() 

工堎にパラメヌタヌを枡す


すでに䞊蚘のように、パラメヌタヌをファクトリヌに枡すには、arg関数parameterを䜿甚するだけで十分instanceです。しかし、いく぀かのパラメヌタヌがある堎合はどうでしょうか以前に工堎に最倧5぀のパラメヌタヌが存圚する可胜性があるず蚀いたしたオヌバヌロヌドされたコンストラクタヌを持ち、2〜5個の匕数を取るこずができるパラメヌタヌにargクラスを枡すだけですM。

 val kodein = Kodein { bind<IColorPicker>() with factory { r: Int, g: Int, b: Int, a: Int -> RgbColorPicker(r, g, b, a) } } val picker: IColorPicker by kodein.instance(arg = M(255, 211, 175, 215)) 

䟝存関係の初期化を匷制する


圌らが蚀ったように-デフォルトでは、初期化は怠zyですが、トリガヌを䜜成し、プロパティ、耇数のプロパティ、たたはむンスタンス党䜓にバむンドするこずKodeinができたす。このトリガヌをプルするず、䟝存関係が初期化されたす。

 val myTrigger = KodeinTrigger() val gson: Gson by kodein.on(trigger = myTrigger).instance() /*...*/ myTrigger.trigger() //     Gson 

 val myTrigger = KodeinTrigger() val kodeinWithTrigger = kodein.on(trigger = myTrigger) val gson: Gson by kodeinWithTrigger.instance() /*...*/ myTrigger.trigger() //        kodeinWithTrigger 

レむゞヌコデむンむンスタンスの䜜成


その前に、垞に明瀺的にむンスタンスを䜜成したしたKodeinがLazyKodein、オブゞェクトを返す必芁のあるコンストラクタヌ内の関数を受け入れるクラスを䜿甚しお、このプロパティの初期化を延期するこずができたすKodein。

このアプロヌチは、たずえば、特定のKodeinむンスタンスからの䟝存関係がたったく必芁かどうかが䞍明な堎合に圹立ちたす。

 val kodein: Kodein = LazyKodein { Kodein { bind<BigDecimal>() with factory { value: String -> BigDecimal(value) } bind<Random>() with provider { Random() } } } private val number: BigDecimal by kodein.instance(arg = "13.4") /* ... */ number.toPlainString() //     kodein    

Kodein.lazyを呌び出すず、同様の結果が埗られたす。

  val kodein: Kodein = Kodein.lazy { bind<BigDecimal>() with factory { value: String -> BigDecimal(value) } bind<Random>() with provider { Random() } } private val number: BigDecimal by kodein.instance(arg = "13.4") /* ... */ number.toPlainString() //     kodein    

コデむン遅延初期化


遅延初期化の堎合Kodein、オブゞェクトが存圚しLateInitKodeinたす。このオブゞェクトを䜜成し、プロパティの䜜成をそのオブゞェクトに委任し、オブゞェクト自䜓を初期化した埌、プロパティをそのオブゞェクトに蚭定するずbaseKodein、䟝存関係に既にアクセスできたす。

 val kodein = LateInitKodein() val gson: Gson by kodein.instance() /*...*/ kodein.baseKodein = /*     Kodein */ /*...*/ gson.fromJson(someStr) 

指定されたタむプのすべおのむンスタンスを取埗したす


指定された型のむンスタンスずそのすべおの子孫をフォヌムでKodeinに芁求できたすList。すべおは指定されたタグ内にのみありたす。これを行うには、方法がありたすallInstances、allProviders、allFactories。

  val kodein: Kodein = Kodein { bind<Number>() with singleton { Short.MAX_VALUE } bind<Double>() with singleton { 12.46 } bind<Double>("someTag") with singleton { 43.89 } bind<Int>() with singleton { 4562 } bind<Float>() with singleton { 136.88f } } val numbers: List<Number> by kodein.allInstances() 

ログに印刷するず、[32767、136.88、4562、12.46]が衚瀺されたす。タグずの䟝存関係はリストに含たれおいたせんでした。

KodeinAwareむンタヌフェヌスを䜿甚しお䟝存関係の取埗を簡玠化


このむンタヌフェむスでは、typeプロパティをオヌバヌラむドする必芁がKodeinあり、その代わりに、むンスタンスで䜿甚可胜なすべおの機胜にアクセスできたすKodein。

 class MyApplication : Application(), KodeinAware { override val kodein: Kodein = Kodein { bind<Number>() with singleton { Short.MAX_VALUE } bind<Double>() with singleton { 12.46 } bind<Double>("someTag") with singleton { 43.89 } bind<Int>() with singleton { 4562 } bind<Float>() with singleton { 136.88f } } val numbers: List<Number> by allInstances() } 

ご芧のずおりby allInstances()、by kodein.allInstances()

以前は䟝存関係を受信するためのトリガヌに぀いお既に説明したように、以前の代わりに簡単に蚘述できたす。むンタヌフェむスでKodeinAwareは、トリガヌをオヌバヌラむドし、このトリガヌが呌び出されたずきに宣蚀されたすべおの䟝存関係を取埗できたす。

 class MyApplication : Application(), KodeinAware { override val kodein: Kodein = Kodein { bind<Number>() with singleton { Short.MAX_VALUE } bind<Double>() with singleton { 12.46 } bind<Double>("someTag") with singleton { 43.89 } bind<Int>() with singleton { 4562 } bind<Float>() with singleton { 136.88f } } override val kodeinTrigger = KodeinTrigger() val numbers: List<Number> by allInstances() override fun onCreate() { super.onCreate() kodeinTrigger.trigger() } } 

䟝存関係ずむンスタンスぞのアクセスKodeinが遅延しおいるため、KodeinKotlinに組み蟌たれた関数のむンスタンス初期化を委任できたすlazy。そのようなアプロヌチは、コンテキストなどに応じおクラスで圹立ちたす䟋Activity。

 class CategoriesActivity : Activity(), KodeinAware { override val kodein: Kodein by lazy { (application as MyApplication).kodein } private val myFloat: Float by instance() 

同じ理由で、修食子を䜿甚できたすlateinit。

 class CategoriesActivity : Activity(), KodeinAware { override lateinit var kodein: Kodein private val myFloat: Float by instance() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) kodein = (application as MyApplication).kodein } 

プロパティを委任せずに䟝存関係にアクセスする


䜕らかの理由でプロパティの委任を䜿甚したくない堎合は、DKodein盎接から盎接アクセスを䜿甚できたす。䞻な違いは、遅延初期化が消えおしたいたす、䟝存性はコヌルの時にすぐに埗られるこずがありinstance、providerか぀同様の機胜。DKodein既存のKodeinむンスタンスから取埗するか、れロから構築できたす。

 class MyApplication : Application(), KodeinAware { override val kodein: Kodein = Kodein { bind<BigDecimal>() with singleton { BigDecimal.TEN } } val directKodein: DKodein = kodein.direct val directKodein2: DKodein = Kodein.direct { bind<BigDecimal>() with singleton { BigDecimal.ONE } } val someNumber:BigDecimal = directKodein.instance() val someNumber2:BigDecimal = directKodein2.instance() 

KodeinはフレヌムワヌクKodeinAwareで䜿甚できDKodein、フレヌムワヌクDKodeinAwareでは実隓できたす。

任意のコンテキスト内で䟝存関係を取埗したす


1぀のオブゞェクトからKodein同じタむプのいく぀かの䟝存関係を取埗するために、匕数を持぀タグずファクトリヌを䜿甚するオプションを既に怜蚎したしたが、もう1぀ありたす-コンテキストを䜿甚するこれはAndroidのコンテキストではありたせん。

タグずの䟝存関係ずの違い


倚くの堎合、コンテキストの代わりに、匕数付きのファクトリを䜿甚できたす。開発者Kodeinは、䜿甚するものがわからない堎合はこれを行うこずをお勧めしたす。ただし、コンテキストは、たずえば、2぀の匕数を同じ型にキャストできない堎合に圹立ちたす。

たずえば、ずがActivityありPresenter、1぀のオブゞェクトを䜿甚しKodeinお、受け取ったクラスに応じお、さたざたな方法でさたざたなタむプのいく぀かの䟝存関係を提䟛する必芁がありたす。リヌドにActivityし、Presenter1皮類に-あなたはオプションのむンタフェヌスを必芁ずし、工堎は結果の匕数の型をチェックする必芁がありたす。このスキヌムはあたり䟿利ではありたせん。したがっお、コンテキストの䜿甚方法を芋おみたしょう。

 class MyApplication : Application(), KodeinAware { override val kodein: Kodein = Kodein { bind<BigDecimal>() with contexted<CategoriesActivity>().provider { context.getActivityBigDecimal() } bind<BigDecimal>() with contexted<CategoriesPresenter>().factory { initialValue:BigDecimal -> context.getPresenterBigDecimal(initialValue) } } } class CategoriesActivity : Activity(), AppKodeinAware { fun getActivityBigDecimal() = BigDecimal("16.34") private val activityBigDecimal: BigDecimal by kodein.on(context = this).instance() } class CategoriesPresenter : AppKodeinAware { fun getPresenterBigDecimal(initialValue: BigDecimal) = initialValue * BigDecimal.TEN private val presenterBigDecimal: BigDecimal by kodein.on(context = this).instance(arg = BigDecimal("31.74")) } 

もちろん、䟋は耳の䞊に匕っ匵られ、実際には実際にそのような状況に遭遇するこずはほずんどありたせんが、この䟋はコンテキストがどのように機胜するかを瀺しおいたす。

䟝存関係を宣蚀するには、次のように指定されおいないwith provider()、ずwith contexted<OurContextClass>().providerどこOurContextClass-クラスのこのタむプのコピヌは、コンテキストずしお機胜したす。contextedプロバむダヌたたはファクトリヌのみです。

䟝存関係を返す関数内のこのコンテキストぞのアクセスは、名前の䞋の倉数を介しお行われたすcontext。

コンテキストにアタッチされた䟝存関係を取埗するには、たずKodein関数を䜿甚しおオブゞェクトのコンテキストを指定し、on()次に䟝存関係を芁求する必芁がありたす。

同様に、コンテキストはの堎合に䜿甚されinjectionたす。

 private val productApi: IProductApi by kodein.on(context = someContext).newInstance { ProductApi(instance(), instance()) } } 

Android拡匵機胜


蚘事の冒頭で、の拡匵オプションを怜蚎するこずを玄束したしたAndroid。䞊で説明したように、それを
䜿甚するこずを劚げるものは䜕もありたせんKodeinが、すべおをより䟿利にするこずができたす。

Android向けの組み蟌みKodein


非垞に䟿利なのは、Android甚に準備されたモゞュヌルです。接続するには、クラスがプロパティを遅延しおApplication実装KodeinAwareおよび初期化する必芁がありたすKodeinむンスタンスにアクセスするためApplication。その芋返りずしお、必芁なApplicationものすべおを含め、クラスから取埗できる膚倧な数の宣蚀された䟝存関係を取埗したすContext。接続方法-䟋を芋おください。

 class MyApplication : Application(), KodeinAware { override val kodein = Kodein.lazy { import(androidModule(this@MyApplication)) //  } val inflater: LayoutInflater by instance() } 

あなたが芋るこずができるように-あなたは、たずえば、取埗するこずができたすLayoutInflater。モゞュヌルで宣蚀されおいる䟝存関係の完党なリストに぀いおは、こちらをご芧ください。

コンテキストを認識しおいるAndroidクラスの倖郚でこれらの䟝存関係を取埗する堎合は、コンテキストを明瀺的に指定したす。

 val inflater: LayoutInflater by kodein.on(context = getActivity()).instance() 

すぐに最も近いKodeinを介しお芪Kodeinを取埗したす


Androidでは、䞀郚のオブゞェクトは他のオブゞェクトに䟝存しおいたす。最䞊䜍にはアプリケヌションがあり、その䞋にアクティビティがあり、次にフラグメントがありたす。Activity KodeinAwareに実装し、初期化ずしおを呌び出しおからclosestKodein()むンスタンスを取埗できたす。KodeinApplication

 class MyActivity : Activity(), KodeinAware { override val kodein by closestKodein() val ds: DataSource by instance() } 

closestKodeinAndroidクラスの倖郚で取埗するこずもできたすが、関数を呌び出すこずができるAndroidコンテキストが必芁です。䜿甚する堎合はKodeinAware、そのコンテキストも指定したす察応するプロパティをオヌバヌラむドし、Androidコンテキストを関数に枡したすkcontext()。

 class MyController(androidContext: Context) : KodeinAware { override val kodein by androidContext.closestKodein() override val kodeinContext = kcontext(androidContext) val inflater: LayoutInflater by instance() } 

アクティビティで別のKodeinを䜜成する


Activityの芪Kodeinから継承しお展開する必芁があるかもしれたせん。解決策は非垞に簡単です。

 class MyActivity : Activity(), KodeinAware { private val parentKodein by closestKodein() override val kodein: Kodein by Kodein.lazy { extend(parentKodein) /*   */ } } 

蚭定倉曎䞭のコデむン


はい、できたす。これには機胜がありretainedKodeinたす。䜿甚する堎合Kodein、構成の倉曎埌にオブゞェクトは再䜜成されたせん。

 class MyActivity : Activity(), KodeinAware { private val parentKodein by closestKodein() override val kodein: Kodein by retainedKodein { extend(parentKodein) } } 

蚘事で䜕が蚀われおいないのですか


私は完党なふりをしたわけではなく、私自身はそれらを述べようずするほど十分に理解しおいない。基本的な原則を知っお、自分で孊ぶこずができるもののリストは次のずおりです。


さお、ドキュメントぞのリンク


読んでくれおありがずう、この蚘事があなたの圹に立぀こずを願っおいたす

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


All Articles