皆さん、Dagger2使ってますか?Dagger2!
自分は使ってません!(挨拶
現場の案件で使われているので使ってないっていうのには弊害があるけど、、、
Dagger2ね。自分じゃ最初から組めないと思うのよ。。。
組まれているコードに対して何かしらの修正はできるけども。。。
Dagger2さん、覚えること多すぎませんか?
Modle、Component、Inject、IF、annotation・・・?
たくさんファイルが出来上がる\(^o^)/
って感じで、途方に暮れていたらKoinってライブラリを発見!(今更
ってことで、Koinに触れてみた。
これから各クラスとかは以下の記事で作ったコードに継ぎ足しましたw
Koin諸々実装
依存
def koinVersion ="2.0.1"
implementation "org.koin:koin-androidx-scope:$koinVersion"
implementation "org.koin:koin-androidx-viewmodel:$koinVersion"
implementation "org.koin:koin-androidx-ext:$koinVersion"
// implementation "org.koin:koin-androidx-fragment:$koinVersion" ←公式にはあるって書いてあるのにMavenに存在してないっぽい・・・
どれがどれに対応しているかは理解していないけど、簡単に触れるだけならこれだけでOKだと思う。
AndoridXじゃない場合はorg.koin:koin-androidにすれば良い。
Koin起動
// App
class App : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
androidContext(applicationContext)
modules(modules)
}
}
private val modules = module {
single { RxApiClient() }
single { CoroutineApiClient() }
single<RandomUserRepository> { RandomUserRepositoryImpl(get(), get()) }
viewModel { MainViewModel(get()) }
}
}
これだけでDI出来る!お手軽すぎる!
Dagger2のようにたくさんファイル作らなくてよいし、annotationも覚えなくて良い!w
この例はsingleとviewModelしか使ってないけど、factoryってやつもある。
とりあえず、現状は以下の認識。
single
シングルトンで持ちたいクラスを生成するのに使う。
viewModel
ViewModelクラスを継承したやつに使う、、、はず。
factory
その他、普通にインスタンス作って欲しいやつ
Koin用のクラス
Repository
// ランダムユーザーを取得するリポジトリ
interface RandomUserRepository {
fun getRxDeRandomUser(): Single<RandomUser>
suspend fun getCoroutineDeRandomUser(): RandomUser
}
とりあえず、IFを用意して、、、
// ランダムユーザーを取得するリポジトリ
class RandomUserRepositoryImpl(
private val rxApiClient: RxApiClient,
private val coroutineApiClient: CoroutineApiClient
) : RandomUserRepository {
override fun getRxDeRandomUser(): Single<RandomUser> = rxApiClient.service.getRandomUser()
override suspend fun getCoroutineDeRandomUser(): RandomUser =
coroutineApiClient.service.getRandomUser()
}
実装!
KoinのModleはこんな感じで作成する(前述通り
single<RandomUserRepository> { RandomUserRepositoryImpl(get(), get()) }
最初、get()の数がいまいちわからなかったんだけど、コンストラクタのパラメータ数にあわせるらしい。
Client
// Rxで通信するAPIクラス
class RxApiClient : ApiClient() {
override val baseUrl: String = "https://randomuser.me/"
val service: RxApiService = retrofit.create(RxApiService::class.java)
}
KoinのModleはこんな感じで作成する(前述通り
single { RxApiClient() }
コンストラクタしかない場合は、このままで。
ViewModel
class MainViewModel(
private val randomUserRepository: RandomUserRepository
) : RxViewModel() {
// randomUserRepository使ってなにか処理する
}
KoinのModleはこんな感じで作成する(前述通り
viewModel { MainViewModel(get()) }
ViewModelの場合はviewModelで作成すると色々楽っぽい。
Injectしてみる
// Main
import org.koin.androidx.viewmodel.ext.android.viewModel
class MainFragment : Fragment() {
companion object {
fun newInstance() = MainFragment()
}
private val viewModel:MainViewModel by viewModel()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.main_fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel.apply {
// なにか処理
}
}
}
by viewModel()だけでInjectしてくれる!お手軽!
しかもViewModel側にFactoryを用意しなくてもViewModelのコンストラクタにパラメータを渡せるというお手軽さ。本当に楽すぎる!
唯一実装してみてハマったのが、、、。
by viewModel() ってコード書くと自動でインポートしてくれなくてエラーになるってこと、、、。
by viewModel<MainViewModel>() ってコード書くと自動でインポートしてくれた。
型指定されているからIDEが省略できるよ!って言ってくるから消したけど。
手動でimport文を書くのであればコードに書いたやつを記載すればOKのはず。
Koinを使ってみての所感
楽すぎてDagger2を使うんだったらKoinじゃね?って思いました。
ただ、JavaプロジェクトだとKoinの記述がものすごい面倒そうだったのでJavaプロジェクトの場合はDagger2なのかな?って感想です。
ただDagger2が全く理解できてないから使わないけどw
これから新しく作るKotlinプロジェクトはKoinを導入して行こうかなって思いますよ!