Edited at

[Kotlin用DIフレームワーク] Koinの使い方


Koinとは

タイトルにモロに書いてありますが、


A pragmatic lightweight dependency injection framework for Kotlin developers.

Kotlin開発者向けの実用的な軽量のDI(依存性注入)フレームワーク


です。

Daggerと比べてわかりやすいと感じたので、備忘録のために使い方をまとめます。


使い方(3ステップ)


1. Moduleを宣言する

// いくつかのクラスがあるとします。

class Controller(val service : BusinessService)
class BusinessService()
class MyViewModel(context: Application) : AndroidViewModel(context)

// DSLでそれらを指定してモジュール宣言をするだけです。
val myModule = module {
factory { Controller(get()) }
single { BusinessService() }

viewModel { MyViewModel(androidContext() as Application) }
}

modulefactory などの書き方はDSLですので、詳しくはこちらを参照してください。

コンストラクタがある場合は、get()を使用します。

注入したいクラスをSingletonにしたい場合はsingleを使用します。

また、ViewModelの宣言はDSLでviewModel と指定できます。このとき、Activity-Fragment間でViewModelを共有したいときに用いるAndroidViewModelを継承しているViewModelの場合はコンストラクタにApplicationを持っているので、get()でもいいですが、androidContext() as Applicationでも取得できるらしいので、こちらを使っておきます。

モジュールを宣言する場所は、例えば、diなどのパッケージを切って、その中にmyModuleなどのファイルを作成してその中でトップレベルプロパティとして宣言するのが良いかと。


2. Koinを開始する

class MyApplication : Application() {

override fun onCreate(){
super.onCreate()
// `startKoin` でKoinを開始します。
startKoin {
// Contextを宣言し、
androidContext(this@MyApplication)
// 先ほど宣言したmoduleを指定します。
modules(myModule)
}
}
}

Applicationクラスを継承したクラス内で色々と宣言して startKoin するだけです。


3. インスタンスを注入する

// あとは、Activity内でインスタンスを注入するだけです。

class MyActivity() : AppCompatActivity() {

// serviceプロパティの中へBusinessServiceを遅延注入する。
val service : BusinessService by inject()
val viewModel: MyViewModel by viewModel()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

// もしくは、直接インスタンスを取得する。
val service : BusinessService = get()
}
}

最後は、 by inject() でインスタンスを注入するだけです。

そのプロパティが初めて呼ばれたときに注入しています。

もしくは、get() でも取得可能なのですね。(知らなかった)

viewModelを注入したいときは、by viewModel()を使用します。

DI前だったら

lateinit var vm: MyVeiwModelからの

vm = ViewModelProviders.of(this).get(MyViewModel::class.java)

とかわんさかコード書かないといけなかったから、これがなくなるのは助かる。

Activity, Fragment, Service以外のクラスで注入したい場合は、KoinComponentインターフェースを実装すれば、注入できるようになります(by inject() が使用できるようになります)


終わりに

Koin万歳!!!

Daggerも慣れてしまえば問題ないですが、Koinより学習コストが高めなので(私の理解力の問題かも...)、Daggerを使用しなければならない場合以外は、Koin使いたいなぁ。


※追記

と思っていましたが、シニアエンジニアの方にKoinは動作が遅いということをお聞きし、調べてみました。次のサイトで様々なDIフレームワークでのパフォーマンスを調べてくれてました。

https://github.com/Sloy/android-dependency-injection-performance

Dagger2めちゃくちゃ早くて驚いた。。。

これは学習コスト云々以前に、一人のエンジニアとして品質の面でDaggerを使うべきだなと感じさせられました。


参考(というか公式)

https://insert-koin.io/