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