1. 의존성 주입 프레임워크가 왜 필요할까?
(1) 의존성 파라미터를 생성자에 작성하지 않아도 되니 보일러 플레이트 코드가 줄어든다.
(2) 인터페이스에 구현체를 쉽게 교체하면서 상황에 따라 적절한 행동을 정의할수있다. -> 테스팅을 쉽게 할 수 있다.
2. dagger
- DI Framework(의존성주입 프레임워크)이며 Square사의 dagger와 Google의 dagger2가 있다.
의존성주입이란 외부에서 의존객체를 생성해서 넘겨주는 것을 의미한다. 예를 들어 a class가 b class를 의존할때 b object를 a가 직접 생성하지 않고
외부에서 생성하여 넘겨주면 의존성을 주입했다고 한다.
(2) dagger1 - square
다양한 인젝션 지점, 다양한 바인딩, 다양한 모듈, 다양한 객체 그래프
Dagger1 컴파일 시간에 바인딩을 할뿐만아니라 리플렉션도 사용합니다. 객체를 인스턴스화 할필요가 없더라도, 그래프 합성을 위해서
리플렉션을 사용합니다. Dagger 는 모두가 적합한 방법을 찾아내는 것을 런타임시에 진행합니다.
그래서 가끔 비효율성이 발생하고 디버깅할 때 어려움이 있기도 합니다.
(3) dagger2 - google
Dagger 2 는 의존성을 만들고 제공하는 코드를 직접 쓰는걸 코드 생성으로 대체하자는 아이디어를 가지고 있습니다.
이전 버전과 비교했을 때 많은 부분이 비슷하지만 중요한 차이점들이 있습니다.
리플렉션을 전혀 사용하지 않습니다. 그래프 유효성, 환경설정, 전제조건들을 컴파일 타임에 검사합니다.
쉽게 디버깅 할 수 있고 추적 가능합니다: 의존성 제공과 생성에 대한 전체 call stack 을 볼 수 있습니다.
더 효율적입니다: 구글에 따르면 13% 의 성능 향상이 있다고합니다.
코드 난독화: 손으로 쓴 코드 처럼 ‘method dispatch’ 를 사용합니다.
물론 이런 좋은 기능들은 비용을 수반하고 덜 유연하게 만듭니다. 예를들면 리플렉션을 사용하지 않아서 ‘dynamism’ 이 없습니다.
리플렉션이란 객체를 통해 클래스의 정보를 분석해 내는 프로그램 기법을 말한다.
@Inject: 의존성을 주입을 요청한다. inject 어노테이션으로 의존성 주입을 요청하면 연결된 component가 module로부터 객체를 생성하여 넘겨준다.
@Component: @Inject 와 @Module 사이 다리이며 의존성을 주입하는 역할을 합니다. 컴포넌트는 미리 정의한 모든 타입의 인스턴스를 줍니다. @Component 어노테이션은 인터페이스에다만 달아야합니다 그리고 컴포넌트를 구성하는 모든 @Module 이 달린 클래스 목록을 적어야합니다. 컴포넌트에서 사용하는 모듈들중 하나라도 없다면 컴파일 타임에 에러를 만듭니다. 모든 컴포넌트들은 컴포넌트에 포함된 모듈들을 통해 의존성의 범위를 알 수 있습니다.
- @Subcomponent : component는 계층 관계를 생성할 수 있다. inject를 요청받으면 subcomponent로부터 먼저 의존성을 검색하고 없으면 부모로 올라가면서 검색한다.
- @Module: component에 연결되어 의존성 객체를 생성한다. 생성 후에 scope에 의해 관리되기도 한다.
- @Provide: 의존성 객체를 생성할 메소드 정의
- @Scope: 생성된 객체의 lifecycle범위로 module에서는 scope를 보고 객체를 관리한다.
- @Qualifier: 클래스의 유형이 종속성을 식별하기 불충분할 때 사용하는 어노테이션입니다. 예를 들어 안드로이드의 경우, 많은 경우 컨텍스트의 다양한 타입이 필요합니다, 그래서 “@ForApplication”, “@ForActivity” 같은 식별자 어노테이션을 정의합니다. 컨텍스트를 주입할 때 이 식별자 어노테이션을 이용해서 Dagger가 어떤 타입을 제공할지 정해줍니다.
3. dagger2의 문제점 : activity를 만들 때마다 build() 하고 inject() 해주는 보기 안 좋은 boilerplate들이 많아져서 Gregory Kick이란 분께서 Dagger2의 새로운 사용방법을 제시
(1) ActivityBindingModule : 각각의 Acitivity에 대하여 전부 모듈을 만들어서 하나하나씩 Component에서 선언해주면 지저분해지니까, Activity와 Activity 모듈을 각각 만들고 이를 합쳐주는 module을 하나 또 만든다.
@Module
public abstract class ActivityBindingModule {
@ActivityScoped
@ContributesAndroidInjector(modules = TasksModule.class)
abstract TasksActivity tasksActivity();
@ActivityScoped
@ContributesAndroidInjector(modules = AddEditTaskModule.class)
abstract AddEditTaskActivity addEditTaskActivity();
@ActivityScoped
@ContributesAndroidInjector(modules = StatisticsModule.class)
abstract StatisticsActivity statisticsActivity();
@ActivityScoped
@ContributesAndroidInjector(modules = TaskDetailPresenterModule.class)
abstract TaskDetailActivity taskDetailActivity();
}
(2) AppComponent : AppComponent 딴에서 공급자를 Builder 해줌. 그럼 Application에서 전역적으로 가져다 쓸 수 있다.
@Singleton
@Component(modules = {TasksRepositoryModule.class,
ApplicationModule.class,
ActivityBindingModule.class,
AndroidSupportInjectionModule.class})
public interface AppComponent extends AndroidInjector<ToDoApplication> {
@Component.Builder
interface Builder {
@BindsInstance
AppComponent.Builder application(Application application);
AppComponent build();
}
}
(3) Application : Application에서 이런식으로 build. extends DaggerApplication!
public class ToDoApplication extends DaggerApplication {
@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerAppComponent.builder().application(this).build();
}
}
(4) ActivityModule : Activity 모듈에는 필요한 애들을 선언해준다. 여기서 참고로 @Binds는 @Provides에서 parameter를 그대로 return하는 과정을 줄여준다.
@Module
public abstract class StatisticsModule {
@FragmentScoped
@ContributesAndroidInjector
abstract StatisticsFragment statisticsFragment();
@ActivityScoped
@Binds
abstract StatisticsContract.Presenter statisticsPresenter(StatisticsPresenter presenter);
}
(5) Activity : DaggerAcitivty를 상속받아서 Activity를 생성하면 된다.
public class StatisticsActivity extends DaggerAppCompatActivity {
@Inject
StatisticsPresenter mStatiticsPresenter;
@Inject
StatisticsFragment fragment;
1. DaggerApplication을 상속한다. 얘가 필수적인 dispatcher들을 주입 dispatcher : 먼저 수행되야 할 작업을 선택해서 공급해주는 놈이라고 한다
2. AndroidSupportInjectionModule.class를 AppComponent에 선언해주어야된다.
3. @ContributesAndroidInjector 얘로 bind를 해준다.