티스토리 뷰

11.  Dagger 바인딩의 종류

@Binds

  • 모듈 내의 추상 메서드에 붙일 수 있음
  • 추상 메서드 앞에 붙여 Binding을 위임 하는 annotation
  • 반드시 하나의 매개 변수만을 가져야 함
  • 매개 변수를 반환형으로 바인드할 수 있다.
  • @Provides 메서드 대신 좀 더 효율적으로 사용할 수 있다.
@Module
abstract class MyModuleRandom{
    @Binds
    abstract fun bindRandom(secureRandom: SecureRandom):Random
}
  • Random 객체를 SecureRandom 객체에 바인딩
  • @Binds는 객체를 생성하는 대신 Component 내에 있는 객체를 파라미터로 받아 바인딩하여 좀 더 효율적으로 동작하게 해줌
  • 좀 더 자세한 예제 보러가기 (jaejong님의 블로그 글)

@BindsOptionalOf

  • 모듈 내의 추상 메서드에 붙일 수 있음
  • 매개 변수를 가질 수 없음
  • unit이 아닌 특정 타입을 반환해야함
  • 예외를 던질 수 없음
  • Java Optional 에 대해 구글링해보고 넘어가자
  • Optional 은 메소드의 결과가 null이 될 수 있으며, 클라이언트가 이 상황을 처리해야 할 때 사용하는 것이 좋다.
import dagger.BindsOptionalOf
import dagger.Module

@Module
abstract class CommonModule {
    @BindsOptionalOf
    abstract fun bindOptionalOfString():String
}
import dagger.Module
import dagger.Provides

@Module
class HelloModule {
    @Provides
    fun providesString() = "Hello"
}
  • @BindsOptionalOf 메서드를 통한 의존성의 주입은 다음과 같은 Optional 타입 등으로 주입
import dagger.Lazy
import java.util.*
import javax.inject.Inject
import javax.inject.Provider

class Foo {
    @Inject
    lateinit var str: Optional<String> // @Nullable 바인딩은 허용하지 않음

    @Inject
    lateinit var str2: Optional<Provider<String>>

    @Inject
    lateinit var str3: Optional<Lazy<String>>
}
  • 컴포넌트 내에 Foo가 바인드된 적이 있으면 Optional 상태는 present, 아니라면 absent
  • 특징: 어떤 타입의 의존성이 바인드되었는지 여부와 관계없이 @Inject를 이용해 주입할 수 있다.

[Test를 위한 컴포넌트 2개]

import dagger.Component

@Component(modules = [CommonModule::class, HelloModule::class])
interface StrComponent {
    fun inject(foo: Foo)
}
import dagger.Component

@Component(modules = [CommonModule::class])
interface NoStrComponent {
    fun inject(foo: Foo)
}

[Test code]

    @Test
    fun test_Foo(){
        val foo = Foo()

        DaggerStrComponent.create().inject(foo)
        println(foo.str.isPresent) // true
        println(foo.str.get()) // Hello

        DaggerNoStrComponent.create().inject(foo)
        println(foo.str.isPresent) // false
        println(foo.str.get()) // java.util.NoSuchElementException: No value present
    }
  • 처음에 생성한 컴포넌트는 string을 바인드 받았기 때문에 isPresent == true
  • 두번째 생성한 컴포넌트는 바인드 되지 않아서 isPresent == false
  • 바인드 되지 않은 Optional<String>get()하면 예외가 발생하는 것을 알 수 있었음

@BindsInstance

  • 컴포넌트 빌더의 세터 메서드 또는 컴포넌트 팩토리의 매개 변수에 붙일 수 있음
  • 모듈이 아닌 외부로 부터 생성된 인스턴스를 빌더 또는 팩토리를 통해서 넘겨줌으로써 컴포넌트가 해당 인스턴스를 반인드
  • 이러한 인스턴스들은 마찬가지로 @Inject가 붙은 필드, 생성자, 메서드에 주입 가능

예제

import dagger.BindsInstance
import dagger.Component

@Component
interface BindsComponent {
    fun inject(foo: Foo)

    @Component.Builder
    interface Builder {
        @BindsInstance
        fun setString(str: String): Builder
        fun build(): BindsComponent
    }
}
import javax.inject.Inject

class Foo {
    @Inject
    lateinit var str: String
}

테스트 코드

    @Test
    fun test_bindsInstance() {
        val hello = "Hello World"
        val foo = com.lilcode.hellodagger.bindsInstance.Foo()
        val component = DaggerBindsComponent.builder()
            .setString(hello)
            .build()
        component.inject(foo)
        assertEquals("Hello World", foo.str)
    }
  • 외부로부터 생성한 String 객체를 바인드

2021.07.25 - [Android/클린 아키텍처] - [Clean Architecture] 11-범위 지정하기 (@Scope)

2021.07.24 - [Android/클린 아키텍처] - [Clean Architecture] 10-한정자 (@named)

2021.07.23 - [Android/클린 아키텍처] - [Clean Architecture] 09-Lazy 주입 & Provider 주입 (dagger)

해당 글은 '아키텍처를 알아야 앱 개발이 보인다' 를 공부하며 요약 정리한 글 입니다.

댓글
최근에 올라온 글
최근에 달린 댓글
네이버 이웃추가
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함