본문
170609(금) - DI with Dagger2
DI with Dagger2
http://frogermcs.github.io/dependency-injection-with-dagger-2-custom-scopes/
Scope
- Singleton은 API client, database helpers, analytics managers 등에 쓰인다.
- 그러나 DI를 사용한다면 이런식으로 객체를 직접 가져오면 안됨.
- @Inject가 알아서 객체를 잘 가져와 준다.
- Dagger2는 가능한 scope까지 instance를 유지시켜 준다.
ex)
- @ApplicationScope
Application object만큼 오래 살아 남는다.
- @ActivityScope
Activity가 존재하는 한 reference 유지
- CustomScope
그러나 기본적으로 Dagger2에 위와같은 annotation은 없음.
@Singleton 이 기본적으로 제공
Scope ex
- @Singleton
application scope
실제로는 Application 만큼 오래 live한다.
- @UserScope
logging 된 user 와 연관된 class instance scope
- @ActivityScope
Activity 동안 live 하는 instance scope (ex : presenter)
Scopes lifecycle
Implementation
- Implement proper configuration of component.
- 2 ways
1. @Subcomponent 사용
- object graph 전체에 access 가능
2. Component dependencies
- component interface에 노출된 object에만 access 가능
- AppComponent의 Subcomponent인 Usercomponent와 SplashActivityComponent는 AppModule, GithubApiModule에서 생성된 instance에 access 가능
@Singleton @Component( modules = { AppModule.class, GithubApiModule.class } ) public interface AppComponent { UserComponent plus(UserModule userModule); SplashActivityComponent plus(SplashActivityModule splashActivityModule); }
- UserComponent는 plus()의 parameter로 전달되는 다른 module을 필요로 한다.
- AppComponent의 graph는 extending 된다.
- AppComponent에서 extend 된 UserComponent에서 가져온 instance는 Singleton 범위이지만,
- UserComponent의 일부인 UserModule에서 생성되는 component는 UserComponent instance 만큼 지속되는 local singleton.
- UserComponent appComponent = appComponent.plus(new UserModule(user)) (UserComponent instance 생성) 마다 UserModule에서 가져오는 object는 다른 instance 이다.
@UserScope @Subcomponent( modules = { UserModule.class } ) public interface UserComponent { RepositoriesListActivityComponent plus(RepositoriesListActivityModule repositoriesListActivityModule); RepositoryDetailsActivityComponent plus(RepositoryDetailsActivityModule repositoryDetailsActivityModule); }
- Annotation create
@Scope @Retention(RetentionPolicy.RUNTIME) // ??? public @interface UserScope { }
- UserComponent의 lifecycle을 담당해야만 한다.
- initialization과 release를 신경써야 한다.
public class GithubClientApplication extends Application { private AppComponent appComponent; private UserComponent userComponent; //... public UserComponent createUserComponent(User user) { userComponent = appComponent.plus(new UserModule(user)); return userComponent; } public void releaseUserComponent() { userComponent = null; } //... }
Under the hood
@Generated("dagger.internal.codegen.ComponentProcessor") public final class UserModule_ProvideRepositoriesManagerFactory implements Factory<RepositoriesManager> { //... @Override public RepositoriesManager get() { RepositoriesManager provided = module.provideRepositoriesManager(userProvider.get(), githubApiServiceProvider.get()); if (provided == null) { throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method"); } return provided; } public static Factory<RepositoriesManager> create(UserModule module, Provider<User> userProvider, Provider<GithubApiService> githubApiServiceProvider) { return new UserModule_ProvideRepositoriesManagerFactory(module, userProvider, githubApiServiceProvider); } }
private final class UserComponentImpl implements UserComponent { //... private UserComponentImpl(UserModule userModule) { if (userModule == null) { throw new NullPointerException(); } this.userModule = userModule; initialize(); } private void initialize() { this.provideUserProvider = ScopedProvider.create(UserModule_ProvideUserFactory.create(userModule)); this.provideRepositoriesManagerProvider = ScopedProvider.create(UserModule_ProvideRepositoriesManagerFactory.create(userModule, provideUserProvider, DaggerAppComponent.this.provideGithubApiServiceProvider)); } //... }
- factory에서 instance를 가져와서 singleton 처럼 저장
- 따라서 single instance를 반환 가능
public final class ScopedProvider<T> implements Provider<T> { //... private ScopedProvider(Factory<T> factory) { assert factory != null; this.factory = factory; } @SuppressWarnings("unchecked") // cast only happens when result comes from the factory @Override public T get() { // double-check idiom from EJ2: Item 71 Object result = instance; if (result == UNINITIALIZED) { synchronized (this) { result = instance; if (result == UNINITIALIZED) { instance = result = factory.get(); } } } return (T) result; } //... }
'Mobile > DI' 카테고리의 다른 글
170712(수) - Dependency Injection with Dagger2 (0) | 2017.07.12 |
---|---|
170707(금) - android-architecture-todo-mvp-dagger (0) | 2017.07.07 |
170609(금) - DI with Dagger2 (0) | 2017.06.09 |
170609 (금) - DI with Dagger2 (0) | 2017.06.09 |
170608(목) - DI with Dagger2 (0) | 2017.06.08 |
댓글