본문 바로가기

Android

[Dagger2] Multi Binding(1)

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

dagger.dev/dev-guide/multibindings

www.charlezz.com/?p=1315

'Android' 카테고리의 다른 글

[Dagger2] Assisted Injection  (0) 2021.05.10
[Dagger2] Multi Binding(3)  (0) 2021.05.03
[Dagger2] Multi Binding(2)  (0) 2021.05.03