2021년 5월 7일 금요일

Kotlin Koin

Kotlin Koin

Koin

Di (Dependense Injection) するためにはDagger2, HiltがあるがKotlinらしくなくて使い方がやや口説くなることがあったのでIntelliJ社はKotlin専用のDIライブラリのKoinを作った。
KoinはKotlinらしく使いやすい、簡単なのでDIなんかを初めて触った素人も即座で使える。

https://insert-koin.io/

早速やって見よう。

  1. build.gradle(Project: xxx) に追加
// Add Maven Central to your repositories if needed
repositories {
  mavenCentral()
}
dependencies {
  // Koin for Android
  compile "org.koin:koin-android:$koin_version"  
 // Testing
 testCompile "org.koin:koin-test:$koin_version"
}
  1. build.gradle(Module: xxx) に追加 (必要なものだけに加減する)
  
def koin_version = "2.1.5"  
  
// For Android  
// Koin for Android  
implementation "org.koin:koin-android:$koin_version"  
// Koin Android Scope features  
implementation "org.koin:koin-android-scope:$koin_version"  
// Koin Android ViewModel features  
implementation "org.koin:koin-android-viewmodel:$koin_version"  
// Koin Android Experimental features  
implementation "org.koin:koin-android-ext:$koin_version"    
testImplementation "org.koin:koin-test:$koin_version"
  
  
// For AndroidX  
// Koin AndroidX Scope features  
implementation "org.koin:koin-androidx-scope:$koin_version"  
// Koin AndroidX ViewModel features  
implementation "org.koin:koin-androidx-viewmodel:$koin_version"  
// Koin AndroidX Fragment features  
implementation "org.koin:koin-androidx-fragment:$koin_version"  
// Koin AndroidX Experimental features  
implementation "org.koin:koin-androidx-ext:$koin_version"
  1. 必要なモジュールを先に作る。
    Entity->Domain(Usecase, Repository) ->Module順。
    今回の例はちょっと違和感があるな。。
//-----------------------//
// package name/domain/entity/Article.kt
//-----------------------//
data class Article(  
    var say : String = "",  
)

//-----------------------//
// package name/domain/usecase/MyUseCase.kt
//-----------------------//
class MyUseCase (  
   private val localRepository: LocalRepository  
)  {  
    fun sayHelloMessageShowUseCase() : String {  
        return localRepository.getHelloMsg()  
    }  
}

//-----------------------//
// package name/domain/repository/LocalRepository.kt
//-----------------------//  
class LocalRepository(  
    private val databaseModule: DatabaseModule  
)  
{  
    fun getHelloMsg() = databaseModule.getDashboard().say  
}

//-----------------------//
// package name/di/DatabaseModule/DatabaseModule.kt
//-----------------------//  
class DatabaseModule(  
    val article: Article  
) {  
    fun getDashboard() : Article {  
        article.say = "Say Hello Koin"  
  return article  
  }  
}
  1. Application ファイルを作ってstartKoinをする。
    本当にシンプルすぎる。
class App : Application() {  
    override fun onCreate() {  
        super.onCreate()  
        startKoin {  
  androidContext(this@App)  
            modules(module {  
  factory { Article() }  
  single { DatabaseModule(get()) }  
  single { LocalRepository(get()) }  
  factory { DashboardUsecase(get()) }    
  viewModel { DashboardViewModel() }
 })  
        }  
  }  
}
  1. ViewModelで使う。KoinでViewModel用のモジュールを使うにはviewModelというキーワードを使わなきゃならないので注意。(viewModel { someClass() } )

普通はのInjectしたいとことにKoinComponentを継承すればできるはず。

//-----------------------//
// package name/ui/dashboard/DashboardViewModel.kt
//-----------------------//  
class DashboardViewModel : ViewModel(), KoinComponent {    
     private val usecase: sayHelloMessageShowUseCase by inject()    
    private val _text = MutableLiveData<String>().apply {  
  value = "This is dash Fragment"  
  }  
  val text: LiveData<String> = _text    
  fun change() {  
        _text.postValue(usecase.changeText())  
    }  
}

//-----------------------//
// package name/ui/dashboard/DashboardFragment.kt
//-----------------------//    
class DashboardFragment : Fragment(), KoinComponent {  
 val dashboardViewModel: DashboardViewModel by viewModel()
       
lateinit var textView: TextView  
override fun onCreateView(  
    inflater: LayoutInflater,  
    container: ViewGroup?,  
    savedInstanceState: Bundle?  
): View? {  
    val root = inflater.inflate(R.layout.fragment_dashboard, container, false)  
    textView = root.findViewById(R.id.text_dashboard)  
    dashboardViewModel.text.observe(viewLifecycleOwner, Observer {  
  textView.text = it  
 })  
    textView.setOnClickListener {  
  dashboardViewModel.change()  
    }  
  return root  
}
  1. TestCodeはこうやる
class SampleKoinTest : KoinTest {  
  
    private val usecase: DashboardUsecase by inject<DashboardUsecase>()  
  
    @get:Rule  
  val koinTestRule = KoinTestRule.create {  
  modules(AppModules().modules)  
    }  
  
  
  @Test  
  fun sampleTest() {  
        assert("Say Hello Koin" == usecase.changeText())  
    }  
}
  1. 終わり。アプリを走ってみるとDIがキチンと動く。

これは。。これは。。素晴らしいすぎる。
どんどんIntellJ社に支配されている感じがする。怖っ。。

KoinはLight weight DI ライブラリーなのでDaggerより多少の機能が足りないかもしれないがこれて十分だ。

0 comments:

댓글 쓰기