개발자이야기
dagger @binds 어노테이션 본문
@Provides 와 @Binds 어노테이션의 차이
@Provides
우선 @Provides 어노테이션을 확인해 보자
@Module
abstract class CarModule2 {
@Provides
fun provideEngine(): Engine {
return LPG()
}
}
provideEngine 이라는 함수명을 갖고 있고 (함수명은 마음대로) 리턴 타입은 Engine 이며
return LPG 객체를 생성하여 반환하게 되어있다. 여기서 Engine 은 interface 이다
class LPG : Engine {
override fun engine(): String {
return "LPG엔진"
}
}
LPG 객체는 위와같은 클래스로 되어있다. 단순 Engine interface를 구현한 구현체 이다.
@Provides 를 사용했을때 컴파일 과정에서 생성되는 코드를 한번 확인해보자
private Car injectCar(Car instance) {
Car_MembersInjector.injectEngine(instance, CarModule_ProvideEngineFactory.provideEngine(carModule));
return instance;
}
위의 코드에서 보면 Car_MembersInjector.injectEngine 주입해 주는 과정에서
(instance, CarModule_ProvideEngineFactory.provideEngine(carModule) )
위의 CarModule_ProvideEngineFactory 클래스에서 엔진을 얻어오는 클래스 파일이 하나 생성되었다.
생성된 코드는 아래와 같다
public final class CarModule_ProvideEngineFactory implements Factory<Engine> {
private final CarModule module;
public CarModule_ProvideEngineFactory(CarModule module) {
this.module = module;
}
@Override
public Engine get() {
return provideEngine(module);
}
public static CarModule_ProvideEngineFactory create(CarModule module) {
return new CarModule_ProvideEngineFactory(module);
}
public static Engine provideEngine(CarModule instance) {
return Preconditions.checkNotNull(instance.provideEngine(), "Cannot return null from a non-@Nullable @Provides method");
}
}
위의 생성된 클래스를 기억해 보자. 위의 클래스가 @Binds 를 사용했을땐 통째로 사라진다.
@Provides 어노테이션을 사용했을때 생성되는 파일을 간단하게 알아봤다.
@Binds
@Binds 어노테이션을 사용했을때를 한번 알아보자.
@Module
abstract class CarModule2 {
@Binds
abstract fun bindEngine(engine: LPG): Engine
}
@Binds 어노테이션 의 사용에는 제약이 있다. abstract 함수를 사용해야 하며, 하나의 구현체를 인자로 받아야 한다.
우선 인자로 받은 LPG 클래스를 확인해 보자
class LPG @Inject constructor() : Engine {
override fun engine(): String {
return "LPG엔진"
}
}
LPG 클래스에 constructor 생성자 앞에 @Inject 어노테이션을 붙여 줌으로써 Dagger에게 생성자 주입을 할것이다 라고 알려줘야 한다. 생성자 주입을 Dagger 에게 알려 주었기 때문에 @Binds 를 사용한 함수에서 LPG 인자를 받을 수 있는것이다.
이제 @Binds 어노테이션을 활용했을때 컴파일 과정에서 생성되는 코드를 한번 보자
private Car injectCar(Car instance) {
Car_MembersInjector.injectEngine(instance, new LPG());
return instance;
}
위의 코드를 @Provides 어노테이션을 사용했을때의 코드와 비교해 보자.
@Provides 사용할 때
private Car injectCar(Car instance) {
Car_MembersInjector.injectEngine(instance, CarModule_ProvideEngineFactory.provideEngine(carModule));
return instance;
}
@Binds 사용할 때
private Car injectCar(Car instance) {
Car_MembersInjector.injectEngine(instance, new LPG());
return instance;
}
위의 코드를 확인해 보면 @Binds 를 사용했을때 컴파일 과정의 코드에선 단순히 new LPG 객체의 인스턴스를 사용하려는 곳의 Engine에 주입시켜 주고 있다.
@Provides 에서 설명했던 CarModule_ProvideEngineFactory 클래스 파일이 통째로 사라졌다!!
@Binds 를 사용했을때 @Provides를 사용 했을 때 보다 코드의 양이 40%정도가 감소된다고 한다.
자세한 내용은 https://medium.com/mobile-app-development-publication/dagger-2-binds-vs-pro 참조
직접 컴파일 해보며 테스트 해보며 이해해 보는걸 추천드립니다.
소스는 여기에 https://github.com/boidmy/dagger-Binds
(저도 아직 공부중이라 미흡할 수 있는점 양해 부탁드립니다.)
언제든 지적과 피드백 환영합니다!
'android' 카테고리의 다른 글
mvvm + dagger (0) | 2021.06.07 |
---|---|
android AAC LiveData - switchMap, map (0) | 2021.05.28 |
의존성주입(DI) android dagger (0) | 2021.05.22 |
android recyclerview diffutil (0) | 2021.05.14 |
Retrofit2 url이 만들어지는 패턴 (0) | 2020.06.02 |