정상에서 IT를 외치다

[Dagger] Dagger step5 - Binds와 Multi binding 본문

안드로이드

[Dagger] Dagger step5 - Binds와 Multi binding

Black-Jin 2020. 2. 11. 19:15
반응형

안녕하세요. 블랙진입니다.


이번에는 binds와 multi binding에 대해 알아보는 시간을 가지겠습니다. 그전에! @Provides와 @Named 어노테이션을 사용해 다형화된 객체를 어떻게 불러오는지 혹은 같은 타입을 반환하는 함수를 어떻게 구분하는지 확인해 보겠습니다.



@Provides @Named 사용법


1. CoffeeBean을 추상화 하여 BlackBean과 WhiteBean을 각각 만들어 줍니다.


CoffeeBean

public interface CoffeeBean {
String name();
}


BlackBean

public class BlackBean implements CoffeeBean {

@Override
public String name() {
return "BlackBin";
}
}


WhiteBean

public class WhiteBean implements CoffeeBean {

@Override
public String name() {
return "WhiteBin";
}
}


2. Module에서 같은 타입이지만 다른 객체를 반환하는 함수를 만들어 줍니다. 이때 같은 타입을 반환 하므로 @Named 어노테이션을 사용해 구분해 주어야합니다.

@Module
public class CafeModule {

//...

@Named("black")
@Provides
CoffeeBean provideBlackCoffeeBean() {
return new BlackBean();
}

@Named("white")
@Provides
CoffeeBean provideWhiteCoffeeBean() {
return new WhiteBean();
}
}


3. Component에서 반환할 타입을 정해줍니다. 

@Singleton
@Component(modules = CafeModule.class)
public interface CafeComponent {

CafeInfo cafeInfo();

@Named("black")
CoffeeBean blackCoffeeBean();

@Named("white")
CoffeeBean whiteCoffeeBean();
}


4. 사용예제

//카페를 생성합니다.
CafeComponent cafe = DaggerCafeComponent.create();

CafeInfo cafeInfo = cafe.cafeInfo();
cafeInfo.welcome();

System.out.println("bean : " + cafe.blackCoffeeBean().name());
System.out.println("bean : " + cafe.whiteCoffeeBean().name());


이렇게 같은 데이터 타입을 @Provides와 @Named를 사용해 보았습니다. 이번에는 binds와 multi binding을 사용해 구현해 보겠습니다,




@Provides와 @Binds 비교


이 둘 모두 Module에서 객체를 제공해주는 어노테이션입니다. 그럼 어떤 차이점을 가지고 있을까요? @Provides를 사용하면 @Binds 보다 비효율적인 코드들이 생성되게 됩니다. 약 40%이상 코드가 더 생성된다고 합니다. 그러니 효율적인 면에서 @Binds를 사용하면 좋겠지만 제약이 있습니다. @Binds 어노테이션은 오직 1개의 파라미터를 가지고 있어야 하며 abstract 함수로 호출해야 합니다. 더 자세한 설명은 @Binds vs @Provides를 확인해주세요 :)




Binds 사용방법


1. CafeModule을 abstract로 변경해줍니다. 이때 provides는 static으로 선언해서 사용해 주어야 합니다.

@Module
public abstract class CafeModule {

@Singleton
@Provides
static CafeInfo provideCafeInfo() {
return new CafeInfo("BlackJin");
}

@Binds
abstract CoffeeBean provideBlackCoffeeBean(BlackBean blackBean);
}


2. BlackBean의 @Inject를 추가해 줍니다.

public class BlackBean implements CoffeeBean {

@Inject
BlackBean() {

}

@Override
public String name() {
return "BlackBin";
}
}


이렇게 하면 CoffeeBean 객체를 BlackBean 이란 객체에 바인딩 하는 것을 의미합니다. 그럼 어떻게 가져와서 사용할까요?


3. 간결하게 CafeComponent에서 coffeeBean()을 가져와 사용하면 됩니다. (이 예제에서는 WhiteBean은 아직 생성하지 않았습니다.)

@Singleton
@Component(modules = CafeModule.class)
public interface CafeComponent {

CafeInfo cafeInfo();

CoffeeBean coffeeBean();
}


4. 사용예제

//카페를 생성합니다.
CafeComponent cafe = DaggerCafeComponent.create();

CafeInfo cafeInfo = cafe.cafeInfo();
cafeInfo.welcome();

System.out.println("bean : " + cafe.coffeeBean().name());



MultiBindin 적용하기


그럼 같은 타입을 반환하는 BlackBean과 WhiteBean을 구분해서 바인딩 해보겠습니다.


1. @IntroMap, @StringKey 를 적용해 Map 형태로 데이터를 받아옵니다.

@Module
public abstract class CafeModule {

//...

@Binds
@IntoMap
@StringKey("black")
abstract CoffeeBean provideBlackCoffeeBean(BlackBean blackBean);

@Binds
@IntoMap
@StringKey("white")
abstract CoffeeBean provideWhiteCoffeeBean(WhiteBean whiteBean);
}


2. CafeComponent 에서 Map<String, CoffeeBean> 반환 타입의 함수를 선언합니다.

@Singleton
@Component(modules = CafeModule.class)
public interface CafeComponent {

CafeInfo cafeInfo();

Map<String,CoffeeBean> coffeeBean();
}


3. 사용예제

//카페를 생성합니다.
CafeComponent cafe = DaggerCafeComponent.create();

CafeInfo cafeInfo = cafe.cafeInfo();
cafeInfo.welcome();

System.out.println("bean : " + cafe.coffeeBean().get("black").name());
System.out.println("bean : " + cafe.coffeeBean().get("white").name());


만약 key가 없는 값을 호출하게 되면 NullPointerException이 발생합니다.


예제에서 사용한 코드는 깃허브에서 볼 수 있습니다.

반응형
Comments