您的位置:首页 > 其它

Dagger2学习笔记(二)

2015-11-10 17:37 381 查看
接着上一篇笔记,记录一下@scope这个注解的用法。

代码来自Dagger2Scopes:

ActivityScope的定义方法:

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}


Application级别的component:ApplicationComponent

@Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {

//field injections for the dependencies of the Dagger2ScopesApp
void inject(Dagger2ScopesApp app);

//Exported to child components
Application application();

InteractorExecutor threadExecutor();

MainThread mainThread();
}


Activity级别的component:AbstractActivityComponent、GameListActivityComponent、GameDetailsComponent

//AbstractActivityComponent
@ActivityScope
@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
public interface AbstractActivityComponent {

// Expose the activity to sub-graphs.
Activity activityContext();

Navigator navigator();

ToolbarAnimator getToolbarAnimator();
}


//GameListActivityComponent
@ActivityScope
@Component(dependencies = ApplicationComponent.class, modules = {
ActivityModule.class, GameListModule.class
})
public interface GameListActivityComponent extends AbstractActivityComponent {

//Main activity and game list fragments can get injected through this component.
void inject(MainActivity mainActivity);

void inject(LucasGameListFragment lucasGameListFragment);

GameListPresenter gamePresenter();

LoadGames loadGames();

GameRepository gameRepository();

GameDataSource provideDataSource();
}


@ActivityScope
@Component(dependencies = ApplicationComponent.class, modules = {
ActivityModule.class, GameDetailsModule.class
})
public interface GameDetailsComponent extends AbstractActivityComponent {

void inject(GameDetailsActivity detailsActivity);

void inject(GameDetailsFragment detailsFragment);

GameDetailsPresenter getPresenter();

ChangeBookmarkGameStatus getBookmarkInteractor();
}


ApplicationComponent使用@Singleton 修饰,其他3个component是dependencies 于ApplicationComponent,并且使用@ActivityScope 修饰。

一般使用流程是:

ApplicationComponent在应用的Application里build,这样整个应用生命周期内只有一个ApplicationComponent实例。

所有其他的component都依赖ApplicationComponent,若其他的component中需要可以由ApplicationComponent提供的对象,这些实例由ApplicationComponent负责提供。在这个例子里,加入在GameListActivityComponent 里生成某个对象实例需要传入InteractorExecutor类型参数,则这个参数由 ApplicationComponent负责提供,因为后者有能力提供而且前者依赖于后者。

还是以GameListActivityComponent 为例,这个对象中所有来自ApplicationComponent的实例的scope仍然是和在ApplicationComponent中相同,如果在ApplicationComponent中时singleton的,那依旧是singleton,而由GameListModule本身产生的实例则是本地的(“local singletons”),和GameListActivityComponent 的生命周期相同,所以如果创建另外一个GameListActivityComponent 实例,那么由GameListActivityComponent 本身产生的实例都将是新创建的。这里把英文解释贴出来:

All instances taken from GameListActivityComponent inherited from ApplicationComponent still are singletons (in Application scope). But those which are produced by GameListModule (which is a part of GameListActivityComponent ) will be “local singletons” which live as long as this GameListActivityComponent instance.
So every time we create another GameListActivityComponent instance by calling:

GameListActivityComponent component = DaggerGameListActivityComponent.create();

objects taken from GameListModule are different instances.


下面解释一下为什么定义添加@ActivityScope可以起到管理生命周期的功能:

先看DaggerGameListActivityComponent的生成代码:

// 在initialize方法中:如果module中某个方法被修饰为@ActivityScope
// 则它的初始化方法是这样的
this.provideViewProvider = ScopedProvider.create(MainModule_ProvideViewFactory.create(builder.mainModule));
// 而普通的,没有scope或者singleton修饰的,则是这样的
this.provideLoginInteractorProvider = InteractorsModule_ProvideLoginInteractorFactory.create(builder.interactorsModule);


可以看到,前者是调用了ScopedProvider.create方法生成的,下面看一下ScopedProvider:

public final class ScopedProvider<T> implements Provider<T> {
private static final Object UNINITIALIZED = new Object();

private final Factory<T> factory;
private volatile Object instance = UNINITIALIZED;

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;
}

/** Returns a new scoped provider for the given factory. */
public static <T> Provider<T> create(Factory<T> factory) {
if (factory == null) {
throw new NullPointerException();
}
return new ScopedProvider<T>(factory);
}
}


可以看到静态方法create只是生成了一个新的实例,关键在于get方法,因为所有获得实例的方法是这样调用的:

@Override
public MainPresenter getLoginPresenter() {
return providePresenterProvider.get();
}


都是调用get获取的,下面是关键地方:

使用ScopedProvider的get时,会检测这个实例是否存在,如果是,则直接返回这个实例,否则就调用factory中get方法取得,并保存;

而普通的方式是直接调用factory的get方法取得实例;

最后看一下factory的get方法实现:

@Override
public LoginInteractor get() {
LoginInteractor provided = module.provideLoginInteractor();
if (provided == null) {
throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
}
return provided;
}


可以看到,get方法中时调用module中的provide方法生成实例的,这个就是我们前面定义的@Module中的@Provides方法,每次调用get都会生成一个新的实例

@ActivityScope的秘密就在于此,它只是声明了这个方法生成的实例被ScopedProvider实例持有(是它的一个field),而ScopedProvider实例又被DaggerXXXComponent持有,这样就保证了在component的生命周期内只生成一次这个实例。

学习资料:

Dependency injection with Dagger 2 - Custom scopes
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Dagger2