Dagger2 시작하기 (Java) part2- 런타임 시점에 의존성 주입하기

TPark·2020년 6월 20일
0

안드로이드

목록 보기
7/10

런타임시에 값 주입하기

저번 시리즈에서 만든 Tire 객체의 컨스트럭터에 airPressure 이라는 int 변수가 들어간다고 가정해보자. 이때 이 값을 런타임시에 사용자에게 받아서 사용하고 싶다면 어떻게 해야할까.

Module에 값 주입하기

Tires 객체를 제공하는 WheelsModule에 airPressure에 들어갈 값을 넘겨준뒤에 해당 값을 적용한 객체를 제공하게 만들수 있다.


@Module
public class WheelsModule {
    private int airPressure;

    public WheelsModule(int airPressure) {
        this.airPressure = airPressure;
    }

    @Provides // Provder Method를 정의하는 어노테이션
    static Rims provideRims() {
        return new Rims();
    }

    @Provides
    Tires provideTires() {
        Tires tires = new Tires(airPressure);
        tires.fillAir(); 
        return tires;
    }

    @Provides
    static Wheels provideWheels(Rims rims, Tires tires) {
        return new Wheels(rims, tires);
    }

}

public class Tires {
    private static final String TAG = "Tires";
    private int airPressure;

    public Tires(int airPressure) {
        this.airPressure = airPressure;
    }
    void fillAir() {
        Log.d(TAG, "filling air to tires... + pressure: " + airPressure);
    }
}

public class MainActivity extends AppCompatActivity {
    @Inject
    public Car car;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);

        CarComponent component = DaggerCarComponent.builder()
                .wheelsModule(new WheelsModule(10))
                .build();
        component.inject(this);
        car.drive();
    }
}

이때 WheelsModule에 10이라는 값을 넘겨줘야되기 때문에, 더이상 MainActivity에서 create()를 통해 컴포넌트를 생성할수 없다. 대신 builder를 통해 컴포넌트 객체를 생성하게 된다.

또 다른 방법으로 매개변수에 들어가는 int 값을 @Provides 를 통해 제공하는 방법이 있다. 이때 Dagger2에서는 객체를 판단할때 타입으로 판단하는데 위에서 선언한 air pressure를 포함해 int 타입을 가진 객체가 여러가지가 있을수 있기 때문에 @Named 어노테이션을 사용했다.

@Module
public class DieselEngineModule {
    private int horsePower;

    public DieselEngineModule(int horsePower) {
        this.horsePower = horsePower;
    }

    @Provides
    @Named("horse power") // 여러가지 int 타입을 구별하기 위해 @Named 어노테이션을 사용한다
    int provideHorsePower() {
        return horsePower;
    }

    @Provides
    Engine provideEngine(DieselEngine engine) {
        return engine;
    }
}

public class DieselEngine implements Engine {
    private static final String TAG = "DieselEngine";
    private int horsePower;

	// 제공된 horse power 변수를 사용할때도 마찬가지로 어떤 int 타입의 변수를 사용할지 구별하기 위해 @Named 사용
    @Inject
    public DieselEngine(@Named("horse power") int horsePower) {
        this.horsePower = horsePower;
    }

    @Override
    @Inject
    public void start() {
        Log.d(TAG, "engine start... horse power: " + horsePower);
    }
}

public class MainActivity extends AppCompatActivity {
    @Inject
    public Car car;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);

        CarComponent component = DaggerCarComponent.builder()
                .dieselEngineModule(new DieselEngineModule(200))
                .wheelsModule(new WheelsModule(10))
                .build();
        component.inject(this);
        car.drive();
    }
}

@Component.Builder 사용하기

런타임시에 값을 주입하는 또 다른 방법으로 @Component.Builder 와 @BindsInstance를 사용하는 방법이 있다. @BindsInstance는 보통 모듈의 컨스트럭터를 없애기 위해 사용된다.

아래 예제에서 DieselEngine 객체는 컨스트럭터에서 horsePower와 engineCapacity에 대한 의존성을 직접 주입 받았고, Tires 객체는 컨스터럭터가 아닌 모듈의 provide 메소드에서 airPressure을 주입받는걸 볼수 있다.

예제

@Component(modules = {WheelsModule.class, DieselEngineModule.class})
public interface CarComponent {
    void inject(MainActivity activity);

    @Component.Builder
    interface Builder {
        CarComponent build();

        @BindsInstance
        Builder horsePower(@Named("horse power") int horsePower);

        @BindsInstance
        Builder engineCap(@Named("engine capacity") int engineCap);

        @BindsInstance
        Builder airPressure(@Named("air pressure") int airPressure);
    }
}

@Module
public class DieselEngineModule {
    @Provides
    static Engine provideEngine(DieselEngine engine) {
        return engine;
    }
}

public class DieselEngine implements Engine {
    private static final String TAG = "DieselEngine";
    private int horsePower;
    private int engineCapacity;

    @Inject
    public DieselEngine(@Named("horse power") int horsePower, @Named("engine capacity") int engineCapacity) {
        this.horsePower = horsePower;
        this.engineCapacity = engineCapacity;
    }

    @Override
    @Inject
    public void start() {
        Log.d(TAG, "engine start... horse power: " + horsePower + " engine cap: " + engineCapacity);
    }
}

@Module
public class WheelsModule {
    @Provides
    static Rims provideRims() {
        return new Rims();
    }

    @Provides
    Tires provideTires(@Named("air pressure") int airPressure) {
        Tires tires = new Tires(airPressure);
        tires.fillAir();
        return tires;
    }

    @Provides
    static Wheels provideWheels(Rims rims, Tires tires) {
        return new Wheels(rims, tires);
    }

}

public class Tires {
    private static final String TAG = "Tires";
    private int airPressure;

    public Tires(int airPressure) {
        this.airPressure = airPressure;
    }
    void fillAir() {
        Log.d(TAG, "filling air to tires... + pressure: " + airPressure);
    }
}

public class MainActivity extends AppCompatActivity {
    @Inject
    public Car car;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);

        CarComponent component = DaggerCarComponent.builder()
                .horsePower(20)
                .engineCap(100)
                .airPressure(500)
                .build();
        component.inject(this);
        car.drive();
    }
}

참조

https://www.youtube.com/playlist?list=PLrnPJCHvNZuA2ioi4soDZKz8euUQnJW65

0개의 댓글