예제6
예제 링크 : https://github.com/seyoungcho2/Dagger2Example
이 글은 예제 6과 함께 한다. 예제 6의 코드 구조는 다음과 같다.
Component와 Component Builder
이전 예제에서 generate된 코드를 보면 다음과 같은 코드가 생성되어 있다.
public final class DaggerSchoolComponent implements SchoolComponent {
..
public static final class Builder {
private Builder() {
}
public SchoolComponent build() {
return new DaggerSchoolComponent();
}
}
}
별도로 Builder을 설정하지 않아도 Component내부에 Builder가 만들어져 있다.
이러한 Builder을 설정하기 위해서는 Component Builder을 만들어야 한다. Builder을 따로 설정하지 않으면 위와 같은 Builder가 자동 생성된다.
Builder을 설정하는 방법을 살펴보기 위해 예제6의 AppComponent Interface를 보자.
@Component(modules = [AppModule::class])
interface AppComponent {
fun getApplication() : Application
@Component.Builder
interface Builder {
@BindsInstance
fun name(name: String) : Builder
fun build(): AppComponent
}
}
AppComponent내부에 @Component.Builder라는 Builder 인터페이스를 만들어 놓았다. 이렇게 만들면 컴파일 타임에 다음과 같은 DaggerAppComponent class 파일이 생성된다.
public final class DaggerAppComponent implements AppComponent {
..
private static final class Builder implements AppComponent.Builder {
private String name;
@Override
public Builder name(String name) {
this.name = Preconditions.checkNotNull(name);
return this;
}
@Override
public AppComponent build() {
Preconditions.checkBuilderRequirement(name, String.class);
return new DaggerAppComponent(name);
}
}
}
기존 빌더와 달라진점은 빌더 내부에 name메서드가 들어가고 해당 메서드를 통해 값을 name을 세팅해준다. 이제부터 AppComponent 내부의 모든 모듈들은 name 값 즉, String 값을 별도로 제공(Provide) 하지 않아도 사용할 수 있게 된다.
@BindsInstance
이것이 가능한 이유는 바로 @BindInstance 어노테이션 때문이다. 특정 인스턴스를 제공(Provide)하는 @BindInstance가 Component의 빌더안에 설정되면 해당 Component는 BindInstance에 의해 제공된 Component 및 그 하위의 모든 모듈에 제공(Provide)할 수 있게 된다.
따라서 AppModule이 아래와 같이 설정되어 name : String을 제공(Provide)하는 Provider가 존재하지 않더라도 위의 Component에서 Provide한 name 값을 가져다 쓸 수 있게 된다.
@Module
class AppModule {
@Provides
fun providesApplication(name : String) = Application(name)
}
이를 오브젝트 그래프로 나타내면 다음과 같다.
위의 컴포넌트와 모듈로 다음의 코드를 돌리면
fun main() {
val appComponent: AppComponent = DaggerAppComponent.builder().name("aa").build()
println(appComponent.getApplication().name) // aa
}
aa라는 결과값이 나온다. builder에서 이름을 aa로 설정했기 때문이다.
정리
@BindInstance는 Provider의 특수한 형태이다. @Bind 와 관련된 Annotation은 모두 Provider이며, 모두 특수한 형태로 Provide하는 방식에 지나지 않는다.