Android
Kotlin
Kodein

Kodeinから始めるDI [1] ( for Android )

⚠️便利だから最近Android触り始めた人向けに書きたかっただけで最新のライブラリとかじゃないのでご注意ください.今更Kodeinとか言ってんのかとか言わないで下さい.記事をかく練習も兼ねてます.ご了承下さい.

Kodeinとは

Kodein
KOtlin DEpendence INjection.Kotlinの為のDI.
最近では使うのが当たり前になっているDI(依存注入)ライブラリの一つ.
動的コード生成をするので,コンパイル時にエラーを見つけられないという欠点がある.Daggerが強すぎたのとバグがあったせいで,ほとんど使われなくなってしまって開発が止まっている...早く5.0出て.(使う人が増えたら復活するかも‼︎)
けれど使うのが簡単!だしコードも(個人的に)読みやすくなる.
ちなみにリファレンスが英弱の私でも読めるレベルで優しく綺麗に書いてある.
(classの数が少ない個人のプロダクトで使うことがオススメ.)

この記事はBindingsについてしか書いてないです.

Kodeinの基本的な使い方

※ほとんど公式リファレンスの直訳.

Bindings

Bindingsとは型にインスタンスを結びつける.って意味だと思う.

Bindingsの種類

Provider, Factory, Singleton, EagerSingleton, Multition, Instance, Referenced singleton, Scoped singletons, Tagged bindings, Constant

Provider

毎回新しいinstanceを生成する.

provider-kodein.kt
val kodein = Kodein{
    bind<Niwatori> with provider{Niwatori()}
}

Factory

Providerの引数が取れるversion.

factory-kodein.kt
val kodein = Kodein{
    bind<Hiyoko> with factory{parent: Niwatori -> Hiyoko(parent)}
}

Singleton

1度作ったインスタンスを使い回したいときに使う,@Singletonと同様 生成は1回だけ.初めて呼び出したときに生成される.
ただし,メモリリークなどでキャッシュが消える可能性があるのでその点は気をつけなくてはならない.・・・😃

singleton-kodein.kt
val kodein = Kodein{
  bind<Farm> with singleton{Farm()}
}

EagerSingleton

これはSingletonの仲間だけど,bindされた時点でインスタンスが作られる.
私は使った事がない.

eager-singleton.kt
val kodein = Kodein{
   bind<Egg> with eagerSingleton{Niwatori().born()}
}

Multition

SingletonのFactoryバージョン.
引数をとり,その引数が同じ時は同じインスタンスを返す.
なんだかんだこれは凄く便利.
Kodeinのよさここにあり!

multition.kt
val kodein = Kodein{
   bind<Hiyoko> with factory{parentName: String-> Hiyoko(parent)}
}

//ここの書き方については後述,
val hiyoko: Hiyoko = with("Niwatori").kodein.instance()
val hakutyou: Hiyoko = with("Hakutyo").kodein.instance()
val hiyoko2: Hiyoko = with("Niwatori").kodein.instance()

//hiyokoとhiyoko2は同じインスタンス.hakutyouは別のインスタンス.

Instance

既存のインスタンスをbindする.
providerとの違いは()で囲むか{}で囲むかぐらいだと思ってます...(マサカリお願いします.)

instance.kt
val kodein = Kodein{
   bind<Hina> with instance(EggAdapter.bone())
}

Referenced singleton(multitionの特殊なもの)

セイフティーなSingleton.
二種類存在する.
softReference, threadLocal

softRefarence

OutOfMemoryExceptionが起きる前にbindし直してくれる.
singletonじゃなくてこっちを積極的に使って行くべきだと思う.(私は,kodeinを使い始めの頃,singleton使ってメモリリーク起こしまくった.)

threadLocal

thread毎にsingletonになる.
要に,threadが異なると違うインスタンスが返ってくる.

refsingleton.kt
val kodein = Kodein{
   //softReference
   bind<Niwatori> with refSingleton(softReference){Niwatori()}
   //threadLocal
   bind<Hiyoko> with refSingleton(threadLocal){Hiyoko()}
}

Scoped Singleton

Context毎にsingletonになる.
これはbindするものが,引数としてContextを利用する.という時に使う.
Android開発で使うときは,androidActivityScope, androidFragmentScope...etc を指定して使う.
AutoScopeSingletonというのもある.
Contextを持っているproviderと変わりがないらしい.
※AndroidでautoScopeSingletonは使えません.kodein 5.0.0-bata5 が整備されるのを永遠に待とう!!

scopedsingleton.kt
val kodein = Kodein{
   //scopedSingletonの例のみ
   bind<Torinuku> with scopedSingleton(androidContextScope){Toriniku(it as Niwatori)}
}

Tagged bindings

上記で紹介したBind達は,同じ型でもTagで区別させることができる.
同じ型のものを2つ以上Bindする時はTag付が強制される.

taggedbinding.kt
val kodein = Kodein{
   //呼び出す時にTagを"Hokkaido"に指定すると,上の分でbindされたインスタンスが返ってくる.
   bind<Hiyoko>("Hokkaido") with provider{Hiyoko("samui")}
   bind<Hiyoko>("Kagoshima") with provider{Hiyoko()}
}

Constant

定数をbindする時に使う.
インスタンスを与える処理は出来ない.Tag付は必須.

constant.kt
val kodein = Kodein{
   constant("koya") with 10
   constant("shujin") with "Hunachi marunosuke" 
}

補足

途中で説明せずに使っていたところがありますが,

hoge.kt
bind<Hiyoko> with multiton{hoge: Int -> (hoge, instance(), instance("koyo"))}

の様にbindしてある他のインスタンスを使ったbindも可能です.
宣言する順番に制約はありません.

すいません.長くなりそうなので取り敢えずここで一旦切らせて頂きます.
続きの記事もゆっくり書いて上げて行きたいと思います!