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
が遅延しているため、
Kodein
Kotlinに組み込まれた関数のインスタンス初期化を委任できます
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
し、
Presenter
1種類に-あなたはオプションのインタフェースを必要とし、工場は結果の引数の型をチェックする必要があります。このスキームはあまり便利ではありません。したがって、コンテキストの使用方法を見てみましょう。
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()
インスタンスを取得できます。
Kodein
Application
class MyActivity : Activity(), KodeinAware { override val kodein by closestKodein() val ds: DataSource by instance() }
closestKodein
Androidクラスの外部で取得することもできますが、関数を呼び出すことができる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) } }
記事で何が言われていないのですか?
私は完全なふりをしたわけではなく、私自身はそれらを述べようとするほど十分に理解していない。基本的な原則を知って、自分で学ぶことができるもののリストは次のとおりです。
- スコープ
- インスタンスのバインド
- マルチバインディング
- 準備完了コールバック
- 外部ソース
- 消去されたバージョンの落とし穴
- 設定可能なコデイン
- JSR-330の互換性
さて、ドキュメントへのリンク:
読んでくれてありがとう、この記事があなたの役に立つことを願っています!