使用Dagger 2进行依赖注入 - API介绍
原文链接:http://frogermcs.github.io/dependency-injection-with-dagger-2-the-api/ 本文是展示在Android应用中使用Dagger2进行依赖注入的系列文章之一。今天我想深入研究Dagger2的基础,并遍历这个依赖注入框架的所有API。 Dagger 2前文我提到了DI框架带给我们的好处 - 它用少量代码绑定了所有依赖关系。Dagger2是一个DI框架的例子,它生成了大量的代码模板。但是,为什么它更优秀呢?现在,它是唯一一个模拟用户手写自动生成完全可追溯源码的DI框架。这意味着依赖关系图就是魔法门。Dagger2相较其他注入框架缺少动态性(未使用反射),但生成代码的简单性和效率与手写代码无异。 Dagger 2基础Dagger2 API如下: public @interface Component { Class<?>[] modules() default {}; Class<?>[] dependencies() default {}; } public @interface Subcomponent { Class<?>[] modules() default {}; } public @interface Module { Class<?>[] includes() default {}; } public @interface Provides { } public @interface MapKey { boolean unwrapValue() default true; } public interface Lazy<T> { T get(); } 还有其他几个JSR-330(Java中的依赖注入标准)定义的注解,也用在Dagger2中: public @interface Inject { } public @interface Scope { } public @interface Qualifier { } 让我们逐个击破。 @Inject注解首先最重要的DI是 构造器注入构造器使用 public class LoginActivityPresenter { private LoginActivity loginActivity; private UserDataStore userDataStore; private UserManager userManager; @Inject public LoginActivityPresenter(LoginActivity loginActivity,UserDataStore userDataStore,UserManager userManager) { this.loginActivity = loginActivity; this.userDataStore = userDataStore; this.userManager = userManager; } } 所有参数都从依赖图中获取。 public class LoginActivity extends BaseActivity { @Inject LoginActivityPresenter presenter; //... } 本例中的限制是,我们只能对类中的一个构造器使用 域注入另一个方法是对特殊域使用 public class SplashActivity extends AppCompatActivity { @Inject LoginActivityPresenter presenter; @Inject AnalyticsManager analyticsManager; @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); getAppComponent().inject(this); } } 本例中注入过程称为“手工”,方式如下: public class SplashActivity extends AppCompatActivity { //... @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); getAppComponent().inject(this); //Requested depenencies are injected in this moment } } 该调用之前,我们的依赖值为null。 域注入的限制是域不能声明为 //This class is generated automatically by Dagger 2 public final class SplashActivity_MembersInjector implements MembersInjector<SplashActivity> { //... @Override public void injectMembers(SplashActivity splashActivity) { if (splashActivity == null) { throw new NullPointerException("Cannot inject members into a null reference"); } supertypeInjector.injectMembers(splashActivity); splashActivity.presenter = presenterProvider.get(); splashActivity.analyticsManager = analyticsManagerProvider.get(); } } 方法注入最后一个使用 public class LoginActivityPresenter { private LoginActivity loginActivity; @Inject public LoginActivityPresenter(LoginActivity loginActivity) { this.loginActivity = loginActivity; } @Inject public void enableWatches(Watches watches) { watches.register(this); //Watches instance required fully constructed LoginActivityPresenter } } 所有方法参数由依赖图提供。但是为什么我们需要方法注入呢?当我们需要传类实例自身( @Module注解
@Module public class GithubApiModule { @Provides @Singleton OkHttpClient provideOkHttpClient() { OkHttpClient okHttpClient = new OkHttpClient(); okHttpClient.setConnectTimeout(60 * 1000,TimeUnit.MILLISECONDS); okHttpClient.setReadTimeout(60 * 1000,TimeUnit.MILLISECONDS); return okHttpClient; } @Provides @Singleton RestAdapter provideRestAdapter(Application application,OkHttpClient okHttpClient) { RestAdapter.Builder builder = new RestAdapter.Builder(); builder.setClient(new OkClient(okHttpClient)) .setEndpoint(application.getString(R.string.endpoint)); return builder.build(); } } @Provides注解这个注解用在 @Module public class GithubApiModule { //... @Provides //This annotation means that method below provides dependency @Singleton RestAdapter provideRestAdapter(Application application,OkHttpClient okHttpClient) { RestAdapter.Builder builder = new RestAdapter.Builder(); builder.setClient(new OkClient(okHttpClient)) .setEndpoint(application.getString(R.string.endpoint)); return builder.build(); } } @Component注解这个注解用于构建接口,该接口把所有封装在一起。这里,我们定义需要依赖的模块(或组件)。这里定义了那些图依赖应当公开可见(可注入),我们的组件可以注入哪里。 示例代码中 @Singleton @Component( modules = { AppModule.class,GithubApiModule.class } ) public interface AppComponent { void inject(GithubClientApplication githubClientApplication); Application getApplication(); AnalyticsManager getAnalyticsManager(); UserManager getUserManager(); } 而且 @ActivityScope @Component( modules = SplashActivityModule.class,dependencies = AppComponent.class ) public interface SplashActivityComponent { SplashActivity inject(SplashActivity splashActivity); SplashActivityPresenter presenter(); } @Scope注解@Scope public @interface ActivityScope { } JSR-330标准的又一部分。在Dagger2中, 现在是一些不重要,不常使用的注解: @MapKey这个注解用于定义依赖集合(映射和集)。例子是自解释的: 定义 @MapKey(unwrapValue = true) @interface TestKey { String value(); } 提供依赖 @Provides(type = Type.MAP) @TestKey("foo") String provideFooKey() { return "foo value"; } @Provides(type = Type.MAP) @TestKey("bar") String provideBarKey() { return "bar value"; } 使用 @Inject Map<String,String> map; map.toString() // => ?{foo=foo value,bar=bar value}”
@Qualifier
命名依赖 @Provides @Singleton @GithubRestAdapter //Qualifier RestAdapter provideRestAdapter() { return new RestAdapter.Builder() .setEndpoint("https://api.github.com") .build(); } @Provides @Singleton @FacebookRestAdapter //Qualifier RestAdapter provideRestAdapter() { return new RestAdapter.Builder() .setEndpoint("https://api.facebook.com") .build(); } 注入依赖 @Inject @GithubRestAdapter RestAdapter githubRestAdapter; @Inject @FacebookRestAdapter RestAdapter facebookRestAdapter; 全部介绍完毕。我们已经了解了Dagger 2 API的所有重要组件。 App实例现在,是时候上手练练了。我们将实现简单的Github客户端应用,该应用基于Dagger2构建。 想法我们的Github客户端有3个页面和非经简单的用户用例。流程如下:
应用样子如下: 从DI的角度,我们的架构如下: 总之 - 每个activity有自己的依赖图。每个图( 说道 文档中的例子: 预设方法 SomeType getSomeType(); Set<SomeType> getSomeTypes(); @PortNumber int getPortNumber(); 并且我们也定义了我们想注入的依赖(通过方法注入)。例子里, 文档中的例子: 成员注入方法 SomeType getSomeType(); Provider<SomeType> getSomeTypeProvider(); Lazy<SomeType> getLazySomeType(); 实现 我不会涉及过多的点。相反只需要克隆GithubClient代码,并在最新的Android Studio中引入即可。这里有一些要点: Dagger2安装仅需检查 AppComponent 从
区域组件 为了检查Activities组件如何创建的,只需要从 这里我们提供了AppComponent实例(因为 剩下的就靠你了。认真的——揣摩一切如何结合在一起。而在接下来的文章中我们会尽量密切关注Dagger2(它是如何工作的)。 ##工程的全部源码在这里。 ###作者 如果你喜欢这个文章,你可以分享给你的伙伴或者Twitter上关注我。 写于2015,6月10日。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |