Dagger2의 Multi Binding을 사용하여 여러 모듈에 있는 같은 타입의 객체를 하나의 Set 또는 Map 형태로 관리할 수 있습니다.
1. Set Multi Binding
Set Multi Binding에는 2가지 종류가 있습니다.
@IntoSet 어노테이션을 사용하는 방법과 @ElementsIntoSet 어노테이션을 사용하는 방법
1) @IntoSet
객체 각각을 한개씩 Set에 넣는 방법
Module에는 기존과 동일하게 Provide 함수를 만들고 @IntoSet 어노테이션을 추가합니다.
@Module
public class SetModuleV1 {
@Provides
@IntoSet
String provideHello() {
return "Hello";
}
@Provides
@IntoSet
String provideWorld() {
return "World";
}
}
Component도 기존과 동일합니다.
@Component(modules = SetModuleV1.class)
public interface SetComponentV1 {
void inject(Foo foo);
}
아래는 의존성 주입 받을 Foo Class이다. 모양이 조금 바뀐것을 확인할 수 있습니다.
public class Foo {
final String TAG = "test_dagger";
@Inject
Set<String> strings;
public void print() {
for (String string : strings) {
Log.d(TAG, string);
}
}
}
기존에는 String을 주입받았다면 이제는 Set<String>을 주입받습니다.
그리고 Provide 메소드를 통해 각각의 set에 String을 넣어줍니다.
private void testDagger() {
Foo foo = new Foo();
DaggerSetComponentV1.create().inject(foo);
foo.print();
}
코드를 실행시키면 예상되는것 처럼 아래와 같은 결과가 나옵니다.
D/test_dagger: Hello
D/test_dagger: World
2) @ElementsIntoSet
객체를 한번에 Set에 넣고 Set을 provide 하는 방법
@Module
public class SetModuleV2 {
@Provides
@ElementsIntoSet
Set<String> provideSet() {
return new HashSet<>(Arrays.asList("Sung", "Chul"));
}
}
이번엔 Module이 조금 바뀌었다. 위에 말한 것 처럼 provide 메소드에서 Set을 리턴합니다.
@Component(modules = SetModuleV2.class)
public interface SetComponentV2 {
void inject(Foo foo);
}
public class Foo {
final String TAG = "test_dagger";
@Inject
Set<String> strings;
public void print() {
for (String string : strings) {
Log.d(TAG, string);
}
}
}
Component와 의존성 주입 받을 Foo는 동일
private void testDagger() {
Foo foo = new Foo();
DaggerSetComponentV2.create().inject(foo);
foo.print();
}
동일하게 테스트 해주면 아래와 같은 결과가 나옵니다.
D/test_dagger: Sung
D/test_dagger: Chul
2. Map Multi Binding
Map Multi Binding은 Set Multi Binding과 다르게 @IntoMap 어노테이션만을 사용합니다.
다만 Map 특성상 Key 값이 필요해 Key 어노테이션이 있습니다.
@StringKey, @ClassKey, @IntKey, @LongKey 등이 있습니다.
public class Foo {
}
@Module
public class MapModule {
@Provides
@IntoMap
@StringKey("foo")
static Long provideFooValue() {
return 100L;
}
@Provides
@IntoMap
@ClassKey(Foo.class)
static String provideFooStr() {
return "Foo String";
}
@Provides
@IntoMap
@IntKey(1)
static String provideFooStrByInteger() {
return "Foo String By Integer";
}
}
@StringKey, @ClassKey, @IntKey는 이와같이 사용하면 됩니다.
@Component(modules = MapModule.class)
public interface MapComponent {
Map<String, Long> getLongsByString();
Map<Class<?>, String> getStringsByClass();
Map<Integer, String> getStringsByInteger();
}
Component 구조가 조금 바뀐것을 확인할 수 있습니다.
private void testDagger() {
MapComponent component = DaggerMapComponent.create();
long value = component.getLongsByString().get("foo");
String str1 = component.getStringsByClass().get(Foo.class);
String str2 = component.getStringsByInteger().get(1);
Log.d(TAG, String.valueOf(value));
Log.d(TAG, str1);
Log.d(TAG, str2);
}
테스트 해보면 아래와 같은 결과가 나옵니다.
D/test_dagger: 100
D/test_dagger: Foo String
D/test_dagger: Foo String By Integer
Custom Key
이제 커스텀 키를 만들어봅시다.
public enum MyEnum {
SUNG, CHUL;
}
@MayKey 어노테이션을 사용해 커스텀 키를 만들어 줍니다.
@MapKey
@interface MyEnumKey {
MyEnum value();
}
@MapKey
@interface MyNumberClassKey {
Class<? extends Number> value();
}
커스텀 키를 사용해 Component를 만들어 줍니다.
@Component(modules = MyCustomModule.class)
public interface MyCustomComponent {
Map<MyEnum, String> myEnumStringMap();
Map<Class<? extends Number>, String> stringsByNumberClass();
}
private void testDaggerV2() {
MyCustomComponent component = DaggerMyCustomComponent.create();
String str1 = component.myEnumStringMap().get(MyEnum.SUNG);
String str2 = component.myEnumStringMap().get(MyEnum.CHUL);
String str3 = component.stringsByNumberClass().get(BigDecimal.class);
Log.d(TAG, str1);
Log.d(TAG, str2);
Log.d(TAG, str3);
}
테스트 해보면 아래와 같은 결과가 나옵니다.
D/test_dagger: value for SUNG
D/test_dagger: value for CHUL
D/test_dagger: value for BigDecimal
Reference
'Android' 카테고리의 다른 글
[Dagger2] Assisted Injection (0) | 2021.05.10 |
---|---|
[Dagger2] Multi Binding(3) (0) | 2021.05.03 |
[Dagger2] Multi Binding(2) (0) | 2021.05.03 |