[dagger] Dagger2 Practice

Dagger2를 이용하고 적용해보기 위해 실제 프로젝트에서 모듈화하려던 일부 코드를 가져와서 진행한 practice 설명 페이지 입니다.

1. Dagger2 API (annotation)

Dependency Injection을 위해 정의한 자바 표준 annotation을 이용함

@Inject

Dependency Injection framework으로 부터 의존성이 주입되어야 함을 표시합니다.
즉, 의존성 주입을 요청하는 역할을 한다고 보면 됩니다.
Constructor, Field, Method를 이용한 세 가지 방법이 있습니다.

@Inject
public WifiBasedHomeComingAware(Context context, @WifiNetwork WifiStateReceiver wifiStateReceiver) {
    this.context = context;
    this.wifiStateReceiver = wifiStateReceiver;
}
@Inject @Wifi
HomeComingAware homeComingAware;

@Module + @Provides

실제 의존성을 제공하는 역할을 합니다. @Module을 클래스에 표시하고, @Provides는 각각의 메서드에 표시합니다.

@Module
public class HomeComingAwareModule {
    private final static String TAG = HomeComingAwareModule.class.getSimpleName();
    private final Context context;

    public HomeComingAwareModule(Context context) {
        this.context = context;
    }

    @Provides
    Context provideContext() {
        return this.context;
    }

    @Provides @Wifi
    HomeComingAware provideWifiBasedHomeComingAware(WifiBasedHomeComingAware wifiBasedHomeComingAware) {
        return wifiBasedHomeComingAware;
    }

    @Provides @Location
    HomeComingAware provideLocationBasedHomeComingAware(LocationBasedHomeComingAware locationBasedHomeComingAware) {
        return locationBasedHomeComingAware;
    }
}

@Component

의존성을 요청하는 @Inject와 의존성을 제공하는 @Module + @Provides 사이의 연결고리 역할을 합니다.

@Singleton
@Component(dependencies = {WifiBasedHomeComingAwareComponent.class, LocationBasedHomeComingAwareComponent.class}, modules = HomeComingAwareModule.class)
public interface HomeComingAwareComponent {
    void inject(MainActivity activity);
}

@Qualifier

동일한 인터페이스나 상위 클래스를 가지는 하위 클래스의 인스턴스에 대한 의존성을 제공할 때 사용됩니다. 예를 들면, 아래 코드와 같이 동일한 인터페이스를 구현한 두 가지 구현 클래스의 인스턴스에 대해 모두 의존성을 제공하고자 할때 이를 구분하기 위해 @WifiNetwork 이라는 custom annotation이 사용되고 있는데, 이는 @Qualifier annotation을 이용하여 정의된 custom annotation입니다.

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface WifiNetwork {
}
@Module
public class WifiStateReceiverModule {
    @Provides @WifiNetwork
    WifiStateReceiver provideWifiNetworkStateReceiver() {
        Log.d(TAG, "provideWifiNetworkStateReceiver()");
        return new WifiNetworkStateReceiver();
    }

    @Provides @WifiSupplicant
    WifiStateReceiver provideWifiSupplicantStateReceiver() {
        return new WifiSupplicantStateReceiver();
    }
}

2. Dagger2 vs Injection class

Dagger2를 사용하는 것이 Dependency 생성을 한 곳에 모아서 해주는 Injection class를 사용하는 것에 비해 어떤 장점이 있을까?

Dependency를 제공받는 root 클래스의 인스턴스를 주입받을 수 없다 Injection class를 사용하면 아래와 같이 TasksPresenter는 직접 생성해야 함

// Create the presenter
mTasksPresenter = new TasksPresenter(
        Injection.provideUseCaseHandler(),
        tasksFragment,
        Injection.provideGetTasks(getApplicationContext()),
        Injection.provideCompleteTasks(getApplicationContext()),
        Injection.provideActivateTask(getApplicationContext()),
        Injection.provideClearCompleteTasks(getApplicationContext())
        );

반면, Dagger2와 같은 DI framework을 사용하면

@Inject TasksPresenter mTasksPresenter;

Injection.provideTasksPresenter를 추가하더라도 간결해질 뿐 dependency를 요청하는 곳에서 해당 dependency를 생성하는 것은 동일함