使用Dagger 2依赖注入 - 自定义Scope
这章是展示使用Dagger 2在Android端实现依赖注入的系列中的一部分。今天我会花点时间在自定义Scope(作用域)上面 - 它是很实用,但是对于刚接触依赖注入的人会有一点困难。 Scope - 它给我们带来了什么? 几乎所有的项目都会用到单例 - 比如API clients,database helpers,analytics managers等。因为我们不需要去关心实例化(由于依赖注入),我们不应该在我们的代码中考虑关于怎么得到这些对象。取而代之的是 在Dagger 2中,Scope机制可以使得在scope存在时保持类的单例。在实践中,这意味着被限定范围为 简单来说 - scope给我们带来了“局部单例”,生命周期取决于scope自己。 但是需要弄清楚的是 - Dagger 2默认并不提供 Scope - 实践案例为了更好地去理解Dagger 2中的scope,我们直接进入实践案例。我们将要去实现比Application/Activity scope更加复杂一点的scope。为此我们将使用上一文章中的GithubClient例子。我们的app应需要三种scope:
讲解的 这里有个我们app中scopes和components呈现的简单图表。
单例(Application scope)是最长的scope(在实践中是与application一样长)。UserScope作为Application scope的一个子集scope,它可以访问它的对象(我们可以从父scope中得到对象)。ActivityScope(生命周期与Activity一致)也是如此 - 它可以从UserScope和ApplicationScope中得到对象。 Scope生命周期的例子这里有一个我们app中scope生命周期的案例: 单例的生命周期是从app启动后的所有的时期,当我们从Github API(在真实app中是用户登录之后)得到了 实现 在Dagger 2中,Scope的实现归结于对Components的一个正确的设置。一般情况下我们有两种方式 - 使用 我选择第一种使用 我们从 @Singleton
@Component(
modules = {
AppModule.class,GithubApiModule.class
}
)
public interface AppComponent {
UserComponent plus(UserModule userModule);
SplashActivityComponent plus(SplashActivityModule splashActivityModule);
}
它将会是其它subcomponents的根Components: 作为替代,我们新增了两个方法:
这表示,我们可以从 这些方法的命名法则是:返回类型是subcomponent类,方法名字随意,参数是这个subcomponent需要的modules。 如你所见, @UserScope
(
modules = {
UserModule.class
}
)
UserComponent {
RepositoriesListActivityComponent plus(RepositoriesListActivityModule repositoriesListActivityModule);
RepositoryDetailsActivityComponent plus(RepositoryDetailsActivityModule repositoryDetailsActivityModule);
}
当然 @Scope
(RetentionPolicy.RUNTIME)
public UserScope {
}
我们可以从 并且更重要的是所有scope的东西都发生在这里。所有 UserComponent 中从AppComponent 继承过来的仍然shi是单例的(是 Applicaton scope)。但是UserModule (UserComponent 的那部分)创建的对象将会是“局部单例”,它的生命周期跟UserComponent 实例是一样的。
所以,每次一创建另一个 UserComponent appComponent = appComponent.plus(new UserModule(user))
从 但是这里很重要的一点是 - 我们要负责 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;
}
//...
}
Dagger 2中的Scope - 内部实现查看它的内部的工作原理是很不错的。通常在这种情况下可以确定,在Dagger 2的scope机制下并不存在什么魔法。 UserModule.provideRepositoriesManager()方法开始研究。它提供了 @Generated("dagger.internal.codegen.ComponentProcessor")
public final UserModule_ProvideRepositoriesManagerFactory implements Factory<RepositoriesManager> {
//...
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;
}
static Factory<RepositoriesManager> create(UserModule module,Provider<User> userProvider,Provider<GithubApiService> githubApiServiceProvider) {
return new UserModule_ProvideRepositoriesManagerFactory(module,userProvider,githubApiServiceProvider);
}
}
UserModule_ProvideRepositoriesManagerFactory仅仅是一个工厂模式的现实,它从 UserModule_ProvideRepositoriesManagerFactory在 private UserComponentImpl UserComponent {
//...
private UserComponentImpl(UserModule userModule) {
if (userModule == null) {
new NullPointerException();
}
this.userModule = userModule;
initialize();
}
private initialize() {
this.provideUserProvider = ScopedProvider.create(UserModule_ProvideUserFactory.create(userModule));
this.provideRepositoriesManagerProvider = ScopedProvider.create(UserModule_ProvideRepositoriesManagerFactory.create(userModule,provideUserProvider,DaggerAppComponent.this.provideGithubApiServiceProvider));
}
//...
}
provideRepositoriesManagerProvider对象在我们每次请求它时负责提供 ScopedProvider<T> Provider<T> {
//...
ScopedProvider(Factory<T> factory) {
assert factory != null;
this.factory = factory;
}
("unchecked") // cast only happens when result comes from the factory
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;
}
//...
}
再简单不过了吧?第一次调用 在这里你可以查看ScopedProvider的所有的实现。 就是这样。我们弄清楚了Dagger 2中Scope底层是怎么工作的。现在我们知道,它们没有以任何方式于Scope注解连接。自定义注解只是给了我们一个简单的方式来进行编译时代码校验和标记一个类是单例/非单例。所有的scope相关东西都是与Component的生命周期相关联。 以上就是今天的全部内容。我希望从现在开始scopes会变得更加容易使用。感谢阅读! 代码:以上描述的完整代码可见Githubrepository。 作者Miroslaw Stanek Head of Mobile Development @Azimo
[Android]使用Dagger 2依赖注入 - API(翻译):
[Android]使用Dagger 2依赖注入 - 自定义Scope(翻译):
[Android]使用Dagger 2依赖注入 - 图表创建的性能(翻译):
[Android]Dagger2Metrics - 测量DI图表初始化的性能(翻译): (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |