본문 바로가기

Android 공부

25. 안드로이드 의존성 주입 (Dependency Injection)

의존성 주입은 "각 클래스가 다른 클래스를 알고 있는가" 라는 말로 쉽게 설명할 수 있다.

본격적으로 설명하기에 앞서 아래 예시 코드를 보면,

 

class ViewModel{
	private val repository = Repository()
	
}

class Repository{ }

 

ViewModel 은 Repository 에 의존하고 있다. ViewModel 안에서 Repository 가 선언되면서 ViewModel 은 Repostiory 의 존재를 알고 있기 때문이다. 반면 Repository 는 ViewModel의 존재를 모르기 때문에 의존하지 않는다. 

 

 

 

위와 같은 코드를 보고 아무 문제가 없다고 생각할 수 있겠지만, 위와 같이 코드를 작성할 경우 기능을 수정해야 하거나 새로운 class 를 만들 경우 개발자가 고쳐야 하는 부분이 많다. 의존하고 있는 모든 부분을 수정해야 하기 때문이다. 이를 방지하기 위해 우리는 인터페이스를 만들거나 인자로 받아 생성하는 방법을 사용하기도 한다. 

 

class ViewModel(private val repository : Repository){
	private fun test{}
}

fun main(){
	var viewModel = ViewModel(Repository())
}

 

내용이 수정될 확률이 높거나 자주 수정되는 코드에 직접 의존하지 않고 인터페이스를 사용하거나 위와 같이 인자를 이용하면서 의존성을 역전 시킬 수 있다. 이렇게 코드를 작성하면 class 들이 밀접하게 연결되어 있던 제일 처음의 코드보다 효율성을 높일 수 있다. 

 

 

현재 나는 아래와 같이 인자를 이용해서 객체를 전달받는 비교적 효율적인 방법을 사용하여 개발하고 있다. 개발하면서 아직 큰 문제를 직면하지 못했는데, 의존성 주입에 대해 공부하면서 이를 쉽게 가능하게 해주는 라이브러리가 존재한다는 것을 알게 되었다. 공부하는 단계에서 이 라이브러리를 사용하는 것은 시기 상조라는 생각이 들어 도입까지는 고민하지 않았지만 간단한 사용법 정도만 기록하겠다. 

 


 

안드로이드에서 제공하는 Hilt 라는 라이브러리는 기존의 dagger 라는 라이브러리의 사용성을 높인 라이브러리로 의존성 주입을 돕는다. 

💡 Dagger
  - java 에서 사용할 수 있는 의존성 주입 라이브러리로 hilt 의 기반이 된다.  
  - compile time 에 주입해 compile time 에 에러 체크가 가능해 런타임의 성능을 유지한다. 

 

Hilt 는 주입을 요청하고 객체 생성 방법을 안내에 hilt 에게 알려주는 Inject / 객체를 생성하는 Module / 모듈이 생성한 객체를 인젝트에 주입하는 Component 로 구성되어 있다. 

 

 

Hilt 를 사용하려면, 먼저 Application 객체에 어노테이션을 추가해야 한다. 안드로이드 생명 주기에 맞추어 작동하기 위해서 필요하다.

 

@HiltAndroidApp
class MyApplication : Application(){}

@AndroidEntryPoint
class MainActivity : AppCompatActivity(){
	private val viewModel : MainViewModel by viewModels()
}

@HiltViewModel
class MainViewModel @Inject(private val repository : Repository) : ViewModel(){
	private fun test{}
}

class Repository @Inject(){}

 

viewModel , Repository 의 생성자에 @Inject 어노테이션을 통해서 hilt 에게 객체를 어떻게 생성하는지 알려준다. 

@AndroidEntryPoint, @HiltViewModel 어노테이션은 hilt 에게 viewModel, Activity 임을 알려주기 위해서 필요하다. 

 

 

 

위와는 다르게 코드 수정이 안되는 클래스 (외부 라이브러리 등), Builder 패턴으로 객체를 생성해야 하는 클래스는 Provide Module 로 주입할 객체를 생성한다. 

@Module
@InstallIn(SingleTonComponent::class)
class RetrofitModule{
	@Provides
	@Singleton
	fun pRetrofit(){ // retrofit builder}
}

 


 

의존성 주입의 주요 목적은 객체의 구성과 사용을 분리하는것, 즉 가독성과 코드 재사용을 높이기 위함이 그 목적이다. 클래스가 내부에서 의존성을 가진다면 의존 관계의 클래스들이 서로에게 영향을 주고 받을 수 밖에 없으므로 외부에서 의존성을 주입하여 서로에게 영향을 덜 미치게 하는 것이다. 안정된 인터페이스를 의존하게 하는 등의 대표적인 방법으로 의존성 주입을 실현할 수 있고 이를 편하게 해주는 라이브러리가 위에서 소개한 dagger 와 hilt 라는 것이다. 

 

조금 어려운 개념이기 때문에 다시 한번 공부해서 정리할 예정이다.