接着上一篇笔记,记录一下@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的生命周期内只生成一次这个实例。