Android Gradle
// Add Dagger dependencies
dependencies {
compile ‘com.google.dagger:dagger:2.x’
annotationProcessor ‘com.google.dagger:dagger-compiler:2.x’
}
If you’re using classes in dagger.android you’ll also want to include:compile ‘com.google.dagger:dagger-android:2.x’
compile ‘com.google.dagger:dagger-android-support:2.x’ // if you use the support libraries
annotationProcessor ‘com.google.dagger:dagger-android-processor:2.x’
在Dagger2
的官网上说如果你要使用dagger.android
里面的东西,就需要添加dagger-android
相关的依赖。那这里面都提供了些什么呢?
Android
应用使用Dagger
最主要的困难就是一些Framework
类(如Activity
、Fragment
)是由操作系统实例化的,而Dagger
更好工作的前提是它可以构建所有的注入对象。所以,你只能(不得不)在生命周期方法中进行成员变量注入,这就意味着一些类可能会写成这个样子:
public class FrombulationActivity extends Activity {
@Inject Frombulator frombulator;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// DO THIS FIRST. Otherwise frombulator might be null!
((SomeApplicationBaseType) getContext().getApplicationContext())
.getApplicationComponent()
.newActivityComponentBuilder()
.activity(this)
.build()
.inject(this);
// ... now you can write the exciting code
}
}
这样的确可以实现Android
的依赖注入,但还有两个问题需要我们去面对:
(FrombulationActivity)
知道其注射器。 即使这是通过接口而不是具体类型完成的,它打破了依赖注入的核心原则:一个类不应该知道如何实现依赖注入。于是dagger.android
诞生了…dagger.android
中的类提供了一种简洁化的实现方式。
Activity
对象ApplicationComponent
中注入AndroidInjectModule
,来确保可以绑定Android
的基础组件。一般Android
应用都会提供一个ApplicationComponent
,其他的Component
依赖该ApplicationComponent
即可。
java
@Module
public class AppModule {
@Provides
LogUtil provideLogUtil() {
return new LogUtil();
}
}
@Singleton // 必须要singleton
@Component(modules = AndroidInjectionModule.class, AppModule.class)
public interface AppComponent {
void inject(AppApplication application);
}
- 2.通过@Subcomponent
声明一个实现AndroidInjector
的接口,并且提供一个继承AndroidInjector.Builder
的@Subcomponent.Builder
java
@Subcomponent(modules = AndroidInjectionModule.class)
public interface MainActivitySubcomponent extends AndroidInjector
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder
}
}
- 3.定义完上面的Subcomponent
后,要通过module
将该Module
注入到Application
的modules
列表中
java
java
@Module(subcomponents = MainActivitySubcomponent.class)
abstract class MainActivityModule {
@Binds
@IntoMap
@ActivityKey(MainActivity.class)
abstract AndroidInjector.Factory extends Activity> bindYourActivityInjectorFactory(MainActivitySubcomponent.Builder builder);
@Singleton // 必须用signelton,不然报错错误: A @Module may not contain both non-static @Provides methods and abstract @Binds or @Multibinds declarations
@Provides
static MainActivityPresenter providePresenter() {
return new MainActivityPresenter();
}
}
- 4.将刚才定义的`YourActivityModule.class`添加到`ApplicationComponent`中
@Singleton // 必须要singleton
@Component(modules = {AndroidInjectionModule.class, AppModule.class, MainActivityModule.class})
public interface AppComponent {
void inject(AppApplication application);
}
“`
5.自定义Application
实现HasActivityInjector
并且通过@Inject
注入一个activityInjector()
方法返回的DispathcingAndroidInJector
实例
public class AppApplication extends Application implements HasActivityInjector {
@Inject
DispatchingAndroidInjector dispatchingActivityInjector;
@Override
public void onCreate() {
super.onCreate();
DaggerAppComponent.builder().build().inject(this);
}
@Override
public AndroidInjector activityInjector() {
return dispatchingActivityInjector;
}
}
6.最后,在Activity.onCreate()
方法中在super.onCreate()
之前调用AndroidInjection.inject(this)
public class MainActivity extends AppCompatActivity {
@Inject
LogUtil mLog;
@Inject
MainActivityPresenter mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLog.d(mPresenter.toString());
}
}
执行结果:04-23 19:46:38.443 17096-17096/? E/@@@: com.charon.daggerandroiddemo.MainActivityPresenter@e480d98
但是它是怎么实现的呢?
AndroidInjection.inject()
会从你的Application
中拿到一个DispatchingAndroidInjector
并通过inject(Activity)
把Activity
传了过去。这个DispatchingAndroidInjector
会查找一个你的Activity
类的AndroidInjector.Factory(YourActivitySubcomponent.Builder)
,构建AndroidInjector(YourActivitySubcomponent)
,然后把你的Activity
传给inject(YourActivity)
。
Fragment
实例注入Fragment
实例和注入Activity
类似。同样的去声明subcomponent
,不同的是:
Activity
类型参数替换成Fragment
@ActivityKey
替换成@FragmentKey
HasActivityInjector
替换成HasFragmentInjector
Activity.onCreate()
方法执行注入不同的Fragment
要通过onAttach()
方法注入。 Fragment
的Module
的添加位置,与Activity
定义的Module
添加不同,其取决于Fragment
内部所需要的其他绑定的依赖注入;Unlike the modules defined for Activitys, you have a choice of where to install modules for Fragments. You can make your Fragment component a subcomponent of another Fragment component, an Activity component, or the Application component — it all depends on which other bindings your Fragment requires. After deciding on the component location, make the corresponding type implement HasFragmentInjector. For example, if your Fragment needs bindings from YourActivitySubcomponent, your code will look something like this:
public class YourActivity extends Activity
implements HasFragmentInjector {
@Inject DispatchingAndroidInjector fragmentInjector;
@Override
public void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
// ...
}
@Override
public AndroidInjector fragmentInjector() {
return fragmentInjector;
}
}
public class YourFragment extends Fragment {
@Inject SomeDependency someDep;
@Override
public void onAttach(Activity activity) {
AndroidInjection.inject(this);
super.onAttach(activity);
// ...
}
}
@Subcomponent(modules = ...)
public interface YourFragmentSubcomponent extends AndroidInjector<YourFragment> {
@Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<YourFragment> {}
}
@Module(subcomponents = YourFragmentSubcomponent.class)
abstract class YourFragmentModule {
@Binds
@IntoMap
@FragmentKey(YourFragment.class)
abstract AndroidInjector.Factory extends Fragment>
bindYourFragmentInjectorFactory(YourFragmentSubcomponent.Builder builder);
}
@Subcomponent(modules = { YourFragmentModule.class, ... }
public interface YourActivityOrYourApplicationComponent { ... }
上面主要用到了这几个类:
AndroidInjection
:注入Android
核心库的基本类型的实例AndroidInjector
:注入Android
库的类型的接口,T
为Android
库的基本类型T
,比如Activity
、Fragment
、BroadcastReceive
等;AndroidInjector.Factory
:AndroidInjector
的工厂类接口DispatchingAndroidInjector
:其为AndroidInjector
接口的实现类,将Android
核心库的的基本类型T
的实例注入Dagger
,该操作是由Android
核心库的类的实例本身执行,而不是Dagger
。卧草,好麻烦。activity
搞一遍、fragment
搞一遍、service
搞一遍….
弄到这里我已经迷糊了,在dagger.android
这里我废了老半天劲,中间一度不想看了…
每个Activity
都要写一个YourActivityModule
,并且添加到AppComponent
中:
@Singleton // 必须要singleton
@Component(modules = {AndroidInjectionModule.class, AppModule.class, MainActivityModule.class})
public interface AppComponent {
void inject(AppApplication application);
}
那么多Activity
都添加进来,这是简洁个锤子啊
每个YourActivityModule
还要有一个YourActivitySubComponent
文件,同事还需要建立多个SubComponent
@Module(subcomponents = MainActivitySubcomponent.class)
abstract class MainActivityModule {
官网中有这样一段话:
Pro-tip: If your subcomponent and its builder have no other methods or supertypes than the ones mentioned in step #2, you can use @ContributesAndroidInjector to generate them for you. Instead of steps 2 and 3, add an abstract module method that returns your activity, annotate it with @ContributesAndroidInjector, and specify the modules you want to install into the subcomponent. If the subcomponent needs scopes, apply the scope annotations to the method as well.
也就是如果您的subcomponent
及其构建器没有第2步中提到的其他方法或超类型,您可以使用@ContributesAndroidInjector
为您生成它们。我们就不需要步骤2和3,取而代之的是添加一个抽象模块方法,该方法返回您的activity
,使用@ContributesAndroidInjector
对其进行注解,并指定要安装到子组件中的模块。 如果子组件需要scopes
,则也可以用@scopes
注解到该方法。
@ActivityScope
@ContributesAndroidInjector(modules = { /* modules to install into the subcomponent */ })
abstract YourActivity contributeYourActivityInjector();
我们可以封装一下:
BaseActivity
在其onCreate()
方法前调用AndroidInjection.inject(this);
BaseActivityComponent
ActivityModule
用AllActivityModule
统一管理dagger
当然不会让你这么费劲,他们提供了更简单的实现
Framework
由于DispatchingAndroidInjector
会在运行时查找合适的AndroidInjector
,基类需要像调用AndroidInjection.inject()
一样实现HasDispatchingActivityInjector/HasDispatchingFragmentInjector
,子类需要做的就是绑定一个对应的@Subcomponent
。如果你的类层次不是很复杂的话Dagger
会提供一些基类(如[DaggerActivity]
和[DaggerFragment]
)。同时Dagger
也会提供[DaggerApplication]
,你需要做的就是继承它并覆写applicationInjector()
方法以返回应该注入Application的component
。
还有下面的类型:
注意:[DaggerBroadcastReceiver]
只适用于在AndroidManifest.xml
文件中静态注册的BroadcastReceiver
,如果你在代码中手动创建注册BroadcastReceiver
,最好采用构造器注入。
就是dagger
提供给了DaggerActivity
、DaggerFragment
、DaggerAppliation
等类,你可以直接去继承该类,实现对应的方法就可以了,不用按照上面一步一步的。
那究竟是怎么用呢?
直接上代码了:
ApplicationModule
类: @Module
public class ApplicationModule {
@Provides
LogUtil provideLogUtil() {
return new LogUtil();
}
}
MainActivityModule
: @Module
public class MainActivityModule {
MainPresenter provideMainPresenter() {
return "main activity module";
}
}
ActivityModule
都放到一个统一的管理类中(为什么必须要有这个类去统一声明对应的Module,后面讲),这里叫ActivityBuilder
不太合适,应该叫ActivityBindingModule
更切合一些: @Module
public abstract class ActivityBuilder {
@ContributesAndroidInjector(modules = MainActivityModule.class)
abstract MainActivity bindMainActivity();
// @ContributesAndroidInjector(modules = Main2ActivityModule.class)
// abstract Main2Activity bindMain2Activity();
// ...
// 以后再写别的Activity只要将其对应的Module添加到这里就好了
}
AndroidInjectionModule
、ApplicationModule
、ActivityBuilder
都注册到AppComponent
中(这三是必须的),然后提供Builder
@Component(modules = {AndroidInjectionModule.class, ApplicationModule.class, ActivityBuilder.class})
public interface AppComponent extends AndroidInjector<AppApplication> {
@Component.Builder // 这个是什么鬼? 为什么要声明它,下面讲
interface Builder {
@BindsInstance
Builder application(AppApplication application);
AppComponent build();
}
void inject(AppApplication application);
}
Application
类继承DaggerApplication
public class AppApplication extends DaggerApplication {
@Override
public void onCreate() {
super.onCreate();
}
@Override
protected AndroidInjector extends DaggerApplication> applicationInjector() {
AppComponent appComponent = DaggerAppComponent.builder().application(this).build();
return appComponent;
}
}
继承后要实现applicationInjector()
方法,也就是制定哪个是应用的injector(the main component AppComponent)
.
这就是为什么要让AppComponent
继承AndroidInjector
的原因。
Activity
继承DaggerActivity
,并且调用方法. public class MainActivity extends DaggerActivity {
@Inject
LogUtil mLog;
@Override
protected void onCreate(Bundle savedInstanceState) {
// 看到没,这里不用写inject了
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLog.d("@@@");
}
}
好了,走你:
04-23 21:19:29.591 21395-21395/? E/@@@: @@@
卧草,方便了没有,好像还可以啊
别忘了上面我们还遗留了两个问题:
ActivityBuilder
并且在里面把Module
列出,并声明ContributesAndroidInjector
@Component.Builder
声明Builder
接口ActivityBuilder : We created this module. This is a given module to dagger. We map all our activities here. And Dagger know our activities in compile time. In our app we have Main and Detail activity. So we map both activities here.
这个问题其实我们在前面讲过。 在讲DaggerActivity
和DaggerFragment
之前。
@Component.Builder: We might want to bind some instance to Component. In this case we can create an interface with @Component.Builder annotation and add whatever method we want to add to builder. In my case I wanted to add Application to my AppComponent.
Note: If you want to create a Builder for your Component, your Builder interface has to has a build(); method which returns your Component.
说白了就是讲Application
和AppComponent
绑定。
public class AppApplication extends DaggerApplication {
@Override
public void onCreate() {
super.onCreate();
}
@Override
protected AndroidInjector extends DaggerApplication> applicationInjector() {
AppComponent appComponent = DaggerAppComponent.builder().application(this).build();
return appComponent;
}
}
support
包的支持像使用Android support library
一样,dagger.android.support
包下面也会提供相应的类。但要注意,当support Fragment
用户需要绑定AndroidInjector.Factory extends android.support.v4.app.Fragment>
时,AppCompat
用户应该继续实现AndroidInjector.Factory extends Activity>
而不是 extends AppCompatActivity>或 extends FragmentActivity>
。
要尽可能的采用构造器注入,因为javac
将确保被set
之前没有字段被引用,这有利于避免空指针异常。但如果你一定要注入成员变量,最好尽早进行注入(越早越好)。也正是因为这样,DaggerActivity
才要在onCreate()
方法中立刻调用AndroidInjection.inject()
再调用super.onCreate()
。DaggerFragment的onAttach()
也是一样,也是为了防止Fragment
重新attach
产生的矛盾。
更多文章请查看AndroidNote
你的star
是我的动力!!!