Dagger-Android使用手册
文档类型:翻译
原文链接 : https://android.jlelse.eu/android-and-dagger-2-10-androidinjector-5e9c523679a3
译者注:转载请注明原文及译文出处,本文仅供学术交流,不作任何商业使用,如有侵权,请联系删除。Dagger版本:2.16
Dagger 2.10版本引入的dagger-android是一个专为Android设计的除了Dagger主模块和dagger-compiler之外的全新的模块,本文中,我们将介绍使用dagger-android的方法步骤,当然,前提是你要具备相关的Dagger知识。
本文主要介绍Activity的注入,但是也可以作为其他Android组件注入的参考
Dagger常用配置
在Android端的Dagger的常用配置包含包含Application Component
以及Application Module
,前者是用来注入Activity,Fragment等Android组件。
Application Component
代码
@Component(modules = { AppModule.class })interface AppComponent { @Component.Builder interface Builder { @BindsInstance Builder application(App application); AppComponent build(); } void inject(FeatureActivity featureActivity);}
Application Module
代码
@Moduleabstract class AppModule { @Provides static Context provideContext(App application) { return application.getApplicationContext(); } @Singleton @Provides static SomeClientApi provideSomeClientApi() { return new SomeClientApiImpl(); }}
App的Application
代码
@Moduleabstract class AppModule { @Provides static Context provideContext(App application) { return application.getApplicationContext(); } @Singleton @Provides static SomeClientApi provideSomeClientApi() { return new SomeClientApiImpl(); }}
因为Android框架已经将这些组件实例化,所以我们必须执行成员注入,使用 @Inject
注解对可见类进行标注,如下:
public class FeatureActivity extends AppCompatActivity { @Inject SomeClientApi mSomeClientApi; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ((App)getApplication()) .getAppComponent() .inject(this); }}
然而,这种方式破坏了依赖注入的核心准则:一个类不应该知道它是如何被注入的
,最新引入的dagger-android模块就是为了解决这个问题——将注入类与注入器分离开来。
使用新的dagger-android模块
首先,将以下Gradle的依赖添加到你的build.gradle
文件中:
// Dagger core dependenciesannotationProcessor 'com.google.dagger:dagger-compiler:2.16'implementation 'com.google.dagger:dagger:2.16'// Dagger Android dependenciesannotationProcessor 'com.google.dagger:dagger-android-processor:2.16'implementation 'com.google.dagger:dagger-android:2.16'implementation 'com.google.dagger:dagger-android-support:2.16'
在我们的项目中,新模块的配置需要不止一个component和module。每一个Activity都需要自己的subComponent并将其与Application的Component连接起来。以下是我建议的类结构:
/| App (extending Application)| AppComponent| AppModule| ContributeAndroidInjectorsModule // 3 + feature/ | FeatureModule // 2 | FeatureActivityModule // 1 | FeatureActivity
正如我们所见,在上文中所提到的典型配置之外额外增加了三个类。每一个feature拥有它自己的component以及module。
注:我使用术语“feature”来描述一个app中的显示界面(或者说一个Activity)。
1.FeatureActivityModule
正如前文提到的,每一个Activity现在需要它自己的subcomponent,为此,Dagger引入了一个非常方便的注解来供我们使用以提醒Dagger生成subcomponent的代码。就像这样:
@Modulepublic abstract class FeatureActivityModule { @ActivityScope @ContributesAndroidInjector(modules = { FeatureModule.class }) abstract FeatureActivity contributeFeatureActivityInjector();}
2.FeatureModule
我们将Activity自身需要的绑配置在这个module中。此module中的绑定仅仅在此Activity和它的subcomponent中有效,除非该module在其他component中使用。假设我们正在使用MVP的设计模式,一下是你通常用来绑定View的方式:
@Moduleabstract class FeatureModule { @ActivityScope @Binds abstract FeatureView provideFeatureView(FeatureActivity featureActivity);}
3.ContributeActivityModule
到目前为止,我们告诉了Dagger为我们的Activity生成subcomponent,但是我们并没有将subcomponent与Applicaiton的Component连接起来。为了实现这个,我们需要另一个module来持有所有Activity的module。这个module将会被包含在Application的Component中。
@Module(includes = { FeatureActivityModule.class // Other Activity modules will be added here})abstract class ContributeActivityModule {}
4.AppComponent
Applicaiton的Component配置(使用Kotlin)
我更喜欢使用Java来写Dagger的module,因为Kotlin缺少static修饰符,所以当我们使用companion object时需要在同一个类中增加额外的
@Module注解
,这是我不太喜欢的。
@Singleton@Component(modules = [ AndroidSupportInjectionModule::class, // 1 ContributeActivityModule::class, // 2 AppModule::class])interface AppComponent : AndroidInjector { // 3 @Component.Builder abstract class Builder : AndroidInjector.Builder() // 4}
(译者注:Java代码如下)
@Singleton@Component(modules = [ AndroidSupportInjectionModule::class, // 1 ContributeActivityModule::class, // 2 AppModule::class])public interface AppComponent extends AndroidInjector<App> { // 3 @Component.Builder abstract class Builder extends AndroidInjector.Builder { }}
注意:AppComponent
中的一些修改:
* 为了使Dagger Android能够正常运行,我们在Application的Component中包含了AndroidSupportInjectionModule
* 包含ContributeActivityModule是为了将Activity的subcomponent与AppComponent连接起来
* AppComponent必须继承自AndroidInjector 并将其泛型设定为Application
类
* Appcomponent的Builder可以选择性的继承AndroidInjector.Builder并提供Application类。因为这个base类已经实现了公共的component builder,这个builder中包含了一个设置Application实例的方法以及另一个构建component的方法,这可以很轻松的为我们介绍一些代码行数。
5.然后我们修改我们的App
文件,使其继承DaggerApplication
并实现基本方法,代码如下
class App : DaggerApplication() { private val appComponent: AndroidInjector by lazy { DaggerAppComponent .builder() .create(this) } override fun applicationInjector(): AndroidInjector { return appComponent }}
(译者注:Java代码如下)
public class App extends DaggerApplication { private AppComponent appCompoent; @Override public void onCreate() { appCompoent = DaggerAppComponent.builder() .application(this) .build(); super.onCreate(); } @Override protected AndroidInjector<? extends DaggerApplication> applicationInjector() { return appCompoent; }}
6.最后,在FeatureActivity
中,我们将之前写的注入Activity的代码删除,同时使其继承自DaggerAppCompatActivity
而不是AppCompatActivity
class FeatureActivity : DaggerAppCompatActivity(), FeatureView { @Inject internal lateinit var presenter: FeaturePresenter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.feature_activity) }}
(译者注:Java代码如下)
public class FeatureActivity extends DaggerAppCompatActivity implements FeatureView { public static final String EXTRA_SOME_ID = "some_id"; @Inject FeaturePresenter presenter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.feature_activity); }}
向Acivity的Component中注入自定义参数
在某些场景下你希望注入某些由Activity自己提供的参数。之前常用的方法是在调用Activity的component的inject()
法法之前,将参数传递给module的构造函数。例如,如果我们遵循MVP的设计模式,我们饿Presenter将会把View作为其构造参数的一部分,这意味着我们需要将Activity作为一个参数传递给module的构造函数。在使用dagger-android之前,写法是这样:
@Moduleclass FeatureModule { private FeatureView view; public FeatureModule(FeatureView view) { this.view = view; } @Provides FeatureView provideView() { return view; }}
同时,在Presenter中我们会使用构造函数注入:
class FeaturePresenter { private final FeatureView view; @Inject Presenter(FeatureView view) { this.view = view; } public void doSomething() { }}
最后,构建Component,传入一个mudle的新实例,并注入Activity:
class FeaturePresenter { private final FeatureView view; @Inject Presenter(FeatureView view) { this.view = view; } public void doSomething() { }}
但是,我们如何使用新的dagger-android模块来实现这个呢?毕竟,我们不再需要手动注入Activity,因此无法像以前那样接触到module的创建。
答案是,我们不再需要这样做了。使用dagger-android模块,Activity已经是图表的一部分了。这到底是什么意思呢?你应该可以记得,我们在FeatureModule
做了一下配置,用于在任何使用FeatureView
的地方,绑定使用FeatureActivity
:
@Modulepublic abstract class FeatureModule { @Binds abstract FeatureView provideFeatureView(FeatureActivity featureActivity); }}
但是,假如我们想通过接受Activity的Intent向Presenter传递参数呢?假设你通过Activity的Intent的extra传递了一个唯一的ID,并且Presenter需要这个ID,例如,Presenter需要这个ID来进行HTTP请求,实现这个的方式就是使用@Named
注解作为限定符,因此我们的Presenter的代码如下:
class FeaturePresenter { private FeatureView featureView; private String someId; @Inject public FeaturePresenter(FeatureView featureView, @Named("someId") String someId) { this.featureView = featureView; this.someId = someId; } public void foo() { featureView.showFoo(); }}
答案是非常简单的,我们给FretureModule增加了一个Provides方法,它将会持有一个FeatureActivity的实例,并从intent的extras中获取我们需要的信息:
@Moduleabstract class FeatureModule { @ActivityScope @Binds abstract FeatureView provideFeatureView(FeatureActivity featureActivity); @ActivityScope @Provides @Named("someId") static String provideSomeId(FeatureActivity featureActivity) { return featureActivity.getIntent().getStringExtra(FeatureActivity.EXTRA_SOME_ID); }}
如前所述,这因为FeatureActivity
已经在图标中,所以这种实现成为可能。
除了Activity之外的注入
如本文开头所提到的,Fragment注入和其他Android组件都不在本文的范围之内。官方文档介绍了注入Fragment对象,我强烈建议您阅读它。还有更多关于Services、Receivers 和ContentProviders的信息。
总结
Dagger-android模块非常接近Android的依赖注入。如果你正在开发一个新的项目并且准备使用Dagger,你一定要使用Dagger-Android的配置。
官方的示例对我来说太简单了,所以你可以看看我自己的Demo。
更多相关文章
- Android jni中数组参数的传递方式
- Android录音时获取分贝值的方法代码实例
- android 手机管理软件 发布开源代码
- 实用代码3
- Android 访问Webservice接口,参数对象不能串行化问题解决(java.lan
- Android中main.xml界面参数笔记
- Android使用代码实现关机/重启