본문 바로가기

Android/DI

[Koin] Koin을 사용하여 의존성 주입을 해보자.

728x90

처음 학습하면서 작성한 글입니다. 필요시 추후 내용을 수정할 예정입니다.

틀린 부분이 있으면 언제든 지적해주면 감사하겠습니다 :)


지난번에 작성한 Dagger2에 이어서, 많이 사용되는 DI인 Koin의 기본적인 사용 방법에 대하여 작성하고자 한다.

Clean Architecture 구조의 예제를 만들 때 사용했던 DI로 Dagger2 보다 쉽게 공부하고 적용할 수 있었던 DI 이다.

 

DI가 무엇인지, 왜 사용하는지에 대한 설명은 이전 Dagger2에 대한 글을 작성할 때 작성했으므로 링크를 추가하고 넘어가도록 하겠다.

https://heegs.tistory.com/78?category=916858 

 

[Dagger2] Dagger2를 사용하여 의존성 주입을 해보자

처음 학습하면서 작성한 글입니다. 필요시 추후 내용을 수정할 예정입니다. 틀린 부분이 있으면 언제든 지적해주면 감사하겠습니다 :) 가장 대중적으로 사용하는 DI 인 Dagger2의 기본적인 사용 방

heegs.tistory.com


우선,

Koin은 무엇인가?

Kotlin DSL로 만들어진 DI Library

 

여기서 DSL란,

Domain Specific Language 의 약어로 특정 분야에 최적화 된 프로그래밍 언어를 뜻한다.

 

즉,

Koin은 코틀린 언어에 최적화된 DI 라이브러리 라고 볼 수 있다.

 

따라서, Koin을 사용했을 때의 장점은 다음과 같다.

 

  • Kotlin 개발 환경에 도입이 쉽다
  • 다른 DI 라이브러리에 비하여(Dagger, Hilt) 러닝 커브가 낮다.
  • Annotation 을 사용하지 않아 Complie 시간이 단축된다.
  • ViewModel 주입을 위한 별도의 라이브러리가 존재한다.

여기서 러닝 커브가 낮다. 라는 면에서는 확실하게 DI 라이브러리를 공부했던 사람이라면 확실하게 느낄 수 있을 것이다.

 

Kotlin 기반으로 프로젝트를 많이 진행하고 있기 때문에 Kotlin DSL로 만들어진 Koin을 프로젝트에 도입하기 쉬울 뿐 아니라 러닝 커브가 다른 라이브러리에 비해 낮아 사용하는데 크게 불편함이 있지 않다.

사실 이것만으로도 DI 라이브러리로 Koin을 선택하기에 큰 영향을 준다고 생각한다.

 

그렇다면,

Koin의 단점은 무엇일까?

 

  • 런타임 중 에러가 발생할 가능성이 있다.
  • 런타임 시 의존성 주입을 해주다 보니, 앱의 퍼포먼스가 떨어질 가능성이 있다.

Dagger를 사용했을 때는 방지가 가능한 런타임 중 에러가 Koin에서는 발생할 수 있다는 단점이 있다.

또한 런타임 시에 DI가 이루어지다보니 앱의 퍼포먼스가 떨어진다고 하는데, 이는 프로젝트의 크기가 커지면 커질수록 부하가 늘어난다고 한다.

따라서, 큰 단위의 프로젝트를 들어가게 되면 어떠한 DI를 사용할 것인지 꼼꼼히 확인 한 후에 채택을 해야할 것으로 보인다.


이제

Koin을 사용해 보자.

 

 

다른 라이브러리와 마찬가지로 Module 범위의 Gradle에 다음과 같이 라이브러리를 추가해준다.

여기서 Unit Test에도 Koin을 사용하고자 한다면

 

testImplementation "org.koin:koin-test:2.2.2"

 

를 추가적으로 작성해주면 된다.

 

Gradle에 라이브러리를 추가하였으면,

Koin을 사용하기 위한 Module과 Module을 등록하고 Koin을 시작하는 부분을 만들어 주면 된다.

 

이런식으로 말이다.

 

생성한 부분에 코드를 작성하기에 앞서, Koin을 사용하기 위한 간단한 클래스를 생성해 준다.

 

 

간단하게 DataSource와 그것을 사용하는 Controller 를 만들어 두었다.

 

단순히 MainActivity에서 해당 클래스들을 생성하여 사용할 수 있겠지만,

Koin을 사용하고자 하는 예제이기 때문에 의존성을 주입하기 위한 작업을 진행해야 한다.

 

 

우선, 별도의 Module 변수를 선언하기 위해 File을 따로 만들어서 생성해 주었다.

module 키워드를 사용하여 모듈을 정의하고, 내부에 의존성을 주입할 객체들을 작성해 준다.

 

의존성 주입을 할 때 사용되는 키워드는 single, factory, get, viewModel 등이 존재한다.

 

1. Single : 싱글톤(Singleton) 객체로 생성한다.
2. Factory : 요청 시 마다 매번 새로운 객체를 생성한다.
3. ViewModel : viewModel에 대한 객체를 생성한다.
4. get : 컴포넌트 내에서 알맞은 의존성을 주입한다.

 

1,2,3번은 위에 작성한 single 부분에 들어가는 키워드이고, get은 해당 객체를 생성할 때 필요한 매개변수 자리에 들어가게 된다.

즉, sampleController 를 생성하기 위해서는 sampleDataSource가 필요한데 이 부분을 get() 을 사용하여 주입하는 것이다.

 

모듈을 선언했으면, 선언한 모듈을 등록하고 Koin을 실행시키는 부분을 작성해야 한다.

 

 

Application 클래스에서 해당 작업은 이루어져야하기 때문에, Application()을 상속받는 클래스가 존재하지 않는다면 별도로 생성해 주어야 한다.

 

Application 클래스의 onCreate 부분에 startKoin 을 호출하여 우리가 하고자하는 작업을 진행시킬 수 있다.

 

androidContext(this@KoinApplication)
modules(sampleModule)

 

androidContext 에는 해당 앱의 context를 넣어주면 되는데, 정말 단순하게 this@ 를 하고 자동완성되는 context를 넣어주면 된다.

 

그 후, modules() 부분을 사용하여 Koin을 통해 DI를 수행하고자 하는 모듈들을 모두 작성해 주면 된다.

이 때, 등록하고자 하는 모듈이 여러개일 경우에는 모듈의 개수만큼 modules를 선언하여 작성해도 되지만, 하나의 modules 키워드를 사용하고 내부에 콤마(,)를 사용하여 여러개의 모듈을 등록할 수 있다.

 

Koin에 모듈을 등록하고 startKoin을 작성해 주었으면

manifest.xml 에 해당 Application 클래스를 사용하겠다고 등록을 해주어야 한다.

 

 

manifest를 확인해 보면

 

android:name=".koin.KoinApplication"

 

이라는 부분이 없을 것이다.

name 속성 값에 선언한 application 클래스를 넣어주면 간단하게 등록이 된다.

 

Koin을 사용할 준비를 모두 끝냈으므로,

의존성을 주입받은 클래스를 사용해보도록 한다.

 

private val controller: SampleController by inject()

 

의존성 주입을 받을 클래스에서 위와 같이 선언을 해준다.

by inject() 를 사용하여 Koin에 등록된 객체를 lazy 하게 주입을 받을 수 있다.

Dagger2에서 @Inject 어노테이션을 사용했던 것과 동일하게, by inject() 키워드를 사용하는 것이다.

 

이처럼 선언을 한 후에, 해당 값을 확인할 수 있도록 로그를 찍어보도록 하자.

 

 

 

이전에 작성했던 Logger Library 를 사용해보자.

 

 

정상적으로 의존성이 주입되어 객체를 사용할 수 있음을 확인 하였다.

 


보통, DI를 사용할 때 위의 예제처럼 사용할 수 있지만

ViewModel에 DI를 사용하여 쓰는 경우가 많다.

 

그렇다면, 

ViewModel에 Koin을 사용해 보자.

 

이전 Dagger2를 사용해본 예제에서 테스트를 진행하고 있기 때문에, SubActivity를 만들고 ViewModel을 추가해 보자.

 

 

SampleController 를 변수로 받고, 내부에 선언된 변수들을 통하여 sampleDatasource에서 초기화 시킨 변수를 사용하도록 하였다.

 

VM을 선언해 주었으면, 해당 VM에 대한 의존성을 주입해주기 위해 모듈에 viewModel을 선언해 주도록 하자.

 

 

위의 sampleModule에서 viewModel을 추가하였다.

실 프로젝트에서는 보통 이처럼 하나의 모듈을 사용하는 것이 아니라,

선언된 모듈의 종류에 따라서 각 다른 파일을 만들고 여러개의 모듈을 등록하여 사용하게 된다.

 

이처럼 ViewModel에 대한 설정이 끝났으면,

의존성을 주입받아 사용해보도록 하자.

 

private val viewModel: SubViewModel by viewModel()

 

위에서 사용했던 by inject()와 다르게 viewModel의 의존성 주입을 위해서는 by viewModel()을 선언해 준다.

 

이렇게 선언했을 때,

 

 

이처럼 viewModel에 빨간줄이 그어지고 오류가 발생하는 경우가 있을 것이다.

 

이렇게 오류가 발생하는 정확한 이유는 모르겠지만,

아마 Koin에서 ViewModel DI를 위한 라이브러리가 추가되어있지 않은 상태에서, viewModel injection을 하려고 해서 발생하는 오류라고 생각한다.

따라서, Koin에서 제공하는 viewModel 관련된 부분을 import 해주면 해결이 가능하다.

 

import org.koin.androidx.viewmodel.ext.android.viewModel

 

해당 라인을 import 해주면 

 

 

이처럼 정상적으로 사용이 가능한 것을 확인할 수 있다.

 

여기서도 마찬가지로, 의존성 주입을 받은 viewModel을 정상적으로 사용이 가능한지 로그를 찍어보자.

 

 

정상적으로 사용이 가능한 것을 확인할 수 있다.

(이 Logger Library는 볼수록 마음에 드는것 같다.)


아주 기본적인 Koin의 사용 방법에 대해서 작성해 보았다.

Dagger2를 사용했을 때 보다 적용하고 사용하는 것이 상당히 쉽다는 것을 다시 한번 느낄 수 있었다.

 

기본적인 사용 방법 외에도, get, getViewModel 키워드 등 사용해보지 않았던 키워드들도 많이 있기 때문에 DI 관련해서는 지속적으로 스터디를 진행해야 할 것 같다.

 

이전 Clean Architecture 예제에 사용된 Koin에 대해서 확인하고 싶은 사람은 다음 GitHub를 확인하면 될 것이다.

https://github.com/HeeGyeong/CleanArchitectureSample

 

GitHub - HeeGyeong/CleanArchitectureSample

Contribute to HeeGyeong/CleanArchitectureSample development by creating an account on GitHub.

github.com

 

또한,

해당 게시글에 사용한 예제는 다음 GitHub 에 올려두었다.

https://github.com/HeeGyeong/DiSample

 

GitHub - HeeGyeong/DiSample: DiSample

DiSample. Contribute to HeeGyeong/DiSample development by creating an account on GitHub.

github.com

 

728x90