Dagger2
url : http://google.github.io/dagger/
요즘 안드로이드 개발에서 Dependency Injection방법을 이용한 개발 방법이 이슈로 자리잡고 있는 듯 합니다. 더군다나 네임드 개발자로 알려진 Jake Wharton 형님이 발표한 자료도 있습니다.
https://speakerdeck.com/jakewharton/dependency-injection-with-dagger-2-devoxx-2014
2라는 숫자가 있는 것을 보면 Dagger1이 있다는 얘기가 됩니다. 처음 Dagger는 Square에서 나왔습니다.
http://square.github.io/dagger/
이 사이트에 가시면 자세한 설명을 보실 수 있어요. 나중에 Dagger에 대한 샘플을 작성해 볼 생각입니다.
Dagger2를 얘기한 이유는 프로젝트가 google github에 있다는 것 때문입니다. 믿고 써보는 google??이라서?
Dagger2에서 중요한 Annotation은 @Module, @Provides, @Component, @Inject 정도 일 것 같습니다.
@Module : Module로 구성되고, 내부에서 주입될 객체들을 provide해주는 것.
@Provides : 객체 주입에 필요한 내용을 리턴해주는것
@Component : Module과 Inject간의 Bridge같은 역활.
@Inject : 객체의 주입.
대충 이런정도의 설명... 저는 참 설명을 못하네요 ㅡ.ㅡ
Dagger2를 이용하기 위한 전반적인 순서 입니다.
gradle 스크립트에 아래와 같은 내용을 추가 해 줍니다.
apply plugin: 'com.neenbedankt.android-apt'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
}
}
android {
........
dependencies {
.......
provided 'javax.annotation:jsr250-api:1.0'
apt 'com.google.dagger:dagger-compiler:2.0'
compile 'com.google.dagger:dagger:2.0'
}
}
그리고 사용할 모델들을 정의 해 줍니다. 저는 아래와 같은 예제를 만들어 보았습니다.
Motor.java
public class Motor {
private int speed;
public Motor() {
this.speed = 0;
}
public int getSpeed() {
return speed;
}
public void accelerate(int value) {
speed = speed + value;
}
public void setSpeed(int value) {
speed = value;
}
public void brake() {
speed = 0;
}
}
Bike.java
public class Bike {
private Motor motor;
public Bike(@NonNull Motor motor) {
this.motor = motor;
}
public void increaseSpped() {
this.motor.setSpeed(this.motor.getSpeed() + 1);
}
public void decreaseSpeed() {
if (this.motor.getSpeed() > 0) {
this.motor.setSpeed(this.motor.getSpeed() - 1);
}
}
public int getSpeed() {
return this.motor.getSpeed();
}
}
그리고 Module을 정의 합니다.
우선 MotorModule.java 입니다. 이건 단순히 Motor객체를 제공해 주는 역활만 합니다.
@Module
public class MotorModule {
@Provides
Motor provideMotor() {
return new Motor();
}
}
BikeModule.java입니다.
@Module(
includes = MotorModule.class
)
public class BikeModule {
@Provides
Bike provideBike(Motor motor) {
return new Bike(motor);
}
}
여기서 보면 Bike객체를 제공해주는 @Provides을 보면 Motor객체가 파라미터로 존재합니다. 과연 이 파라미터는 어디서 제공받고 있을까 라는 의문이 듭니다. 이건 @Module의 includes부분에 보면 MotorModule.class를 포함하고 있고, MotorModule에서 Motor객체를 provides하고 있기에 가능합니다.
이렇게 되면 BikeModule안에서 Motor객체를 필요로 하는 곳에서는 모두 파라미터로 정의하면 Motor객체를 제공받을 수 있습니다.
그리고 Provides된 것을 Inject 하여 사용할 수 있는데 Bike객체를 Inject하여 사용해 볼까 합니다.
그럼 Bike는 어디에서 사용할 까요? 위에서 중요 Annotation중에 @Component를 알려드렸습니다. Module과 Inject간의 Brige같은 역활을 한다고 했는데 사용할 Component는 아래와 같습니다.
MainActivityComponent.java
@Component(
...
modules = {
...
BikeModule.class
}
)
public interface MainActivityComponent extends ActivityComponent {
void inject(@NonNull MainActivity mainActivity);
}
이와 같이 Component를 정의했습니다.
이렇게 Component를 정의하고 컴파일 하면 "DaggerMainActivityComponent가" 만들어 집니다. 이걸 가지고 실질적으로 객체 주입을 진행할 수 있죠.
DaggerMainActivityComponent.builder()
...
.bikeModule(new BikeModule())
.build();
이와 같이 하면 사용할 Component에 대해서는 준비가 끝납니다. 그럼 객체 주입은 어떻게 할까요? 몇가지 방법이 있지만 저는 객체에 @Inject anootation방법을 이용해서 사용 할려고 준비했습니다.
@Inject
Bike bike;
이와 같이 하여 Bike객체 사용에 대한 준비를 합니다.
이건 component에서 inejct라는 메소드를 정의해서 상용할 수 있는 부분입니다 그럼 inject라는 것을 하지 않고 사용할 방법은 있을까요? Component에서 getBike()라는 메소드를 만들어서 사용할 방법도 있긴 합니다.
이 예제에 대한 소스는
https://github.com/drcarter/Dagger2Example
에 올려둿습니다..
저도 Dagger2에 대해서 공부하고 정리하다 보니 설명이 명확하진 않은 듯 합니다.
오히려 맨 위에 Jake Wharton형님이 pt로 설명한 내용이 더 좋을지도요 ㅎㅎㅎ