ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Android] Dagger Binding의 종류
    프로그래밍/Android 2022. 4. 24. 14:03

    @Binds

    - 모듈 내의 추상 메서드에 붙일 수 있다.
    - 반드시 하나의 매개변수만을 가져야 한다.
    - @Provides 메소드 대신 좀 더 효율적으로 사용할 수 있다
        - 객체를 생성하는 대신 컴포넌트 내의 객체를 파라미터로 받아 바인딩 함으로써 좀 더 효율적으로 사용이 가능하다.

    @Binds
    abstract Random bindRandom(SecureRandom secureRandom);

    - 이미 바인드된 SecureRandom을 Random 타입으로 한 번 더 바인드 할 수 있다.

    @BindsOptionalOf

    - 모듈 내의 추상 메소드에 붙일 수 있다.
    - 매개변수를 가질 수 없다.
    - 특정 타입을 반환형으로 가져야 한다.
    - 예외 사항을 던질 수 없다.(Exception)
    - @BindsOptionalOf 메소드를 통한 의존성 주입은 Optional 타입 등으로 주입된다.

    class Foo {
    	@Inject Optional<String> str; //@Nullable 바인딩은 허용하지 않는다.
    	@Inject Optional<Provider<String>> str2;
    	@Inject Optional<Lazy<String>> str3;
    }
    
    @Module
    abstract class CommonModule {
        @BindsOptionalOf
        abstract fun bindsOptionalOfString(): String?
    }
    
    @Module
    class HelloModule {
        @Provides
        fun provideString(): String {
            return "Hello"
        }
    }
    
    @Component(modules = [CommonModule::class, HelloModule::class])
    interface StrComponent {
        fun inject(foo: Foo?)
    }
    
    @Component(modules = [CommonModule::class])
    interface NoStrComponent {
        fun inject(foo: Foo?)
    }
    
    @Test
    fun testFoo() {
        println("testFoo start")
        val foo = Foo()
        DaggerStrComponent.create().inject(foo)
        println("daggerStrComponent -> ${foo.str?.isPresent}")
        println("daggerStrComponent -> ${foo.str?.get()}")
        Assert.assertTrue(foo.str!!.isPresent)
        Assert.assertNotNull(foo.str!!.get())
    
        DaggerNoStrComponent.create().inject(foo)
        Assert.assertFalse(foo.str!!.isPresent)
        println("daggerStrComponent -> ${foo.str?.isPresent}")
        //println("daggerStrComponent -> ${foo.str?.get()}")
        //foo.str.get(); 호출시 NoSuchElementException 발생
        println("testFoo end")
    }

     

    testFoo start
    daggerStrComponent -> true
    daggerStrComponent -> Hello
    daggerStrComponent -> false
    testFoo end


    - String이 바인드 되엇을 때는 present, 바인딩 되지 않았을 때는 absent이다
    - absent 상태일 때 get()메소드로 값을 참조하면 에러가 발생한다.
    - 컴포넌트 내에 Foo가 바인딩 된 적이 있다면 Optional 상태는 present(객체 있음)이고, 그렇지 않다면 absent(객체 없음)이다.

    @BindsInstance

    - 컴포넌트 빌더의 setter 메소드 또는 component factory의 매개변수에 붙일 수 있다.
    - 모듈이 아닌 외부로부터 생성된 인스턴스를 builder또는 factory를 통해 넘겨줌으로써 컴포넌트가 해당 인스턴스를 바인드하게 된다.
    - 이러한 인스턴스들은 모듈로부터 제공되는 인스턴스와 동일하게 @Inject가 붙은 필드, 생성자, 메소드에 주입될 수 있다.

    @Component
    interface BindsComponent {
        fun inject(foo2: Foo2?)
    
        @Component.Builder
        interface Builder {
            @BindsInstance
            fun setString(str: String): Builder?
            fun build(): BindsComponent
        }
    }
    
    class Foo2 @Inject constructor() {
        var str: String? = null
            @Inject set
    }
    
    @Module
    class FooModule {
        @Provides
        fun provideHello(): String {
            return "Hello"
        }
    }
    
    @Test
    fun testBindsInstance() {
        println("testBindsInstance start")
        val hello = "Hello World"
        val foo2 = Foo2()
        val component: BindsComponent = DaggerBindsComponent.builder()
            .setString(hello)!!.build()
        component.inject(foo2)
        println(foo2.str)
        println("testBindsInstance end")
    }
    testBindsInstance start
    Hello World
    testBindsInstance end

    - Builder를 만들고 @BindsInstance가 붙은 setString setter 메소드를 추가했다.
    - 이 메소드에 외부로부터 생성한 객체를 바인드하여 출력하는 예제
    - setString에 hello라는 String을 바인드 한 뒤에 Foo 객체에 inject 하여 foo.str 값이 외부로부터 받은 값으로 변경되었다.

    댓글

Designed by Tistory.