将以下内容添加到build.gradle中(未包括dagger2基本依赖)
dependencies {
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的安卓支持库
很多Android框架类,比如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
}
}
这样做有几个问题
1.复制粘贴代码会使重构变得困难,当越来越多的开发者复制粘贴那段代码,很少有人知道它实际做了什么。
2.更根本的是,它需要请求注入(FrombulationActivity)的类型来了解其注入器。即使这是通过接口而不是具体类型完成的,它打破了依赖注入的核心原则:类不应该知道注入的方式。
所以dagger2开发者弄出了这么一套框架。
怎么实现呢?
1.安装AndroidInjiectionModule在应用程序中以确保这些基本类型所需的所有绑定都可用。(就是引入依赖)
2.首先写一个SubComponent接口扩展AndroidInjector
@Subcomponent(modules = ...)
public interface YourActivitySubcomponent extends AndroidInjector {
@Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder {}
}
3.在定义完Subcomponent后,添加它到你的component分层结构中,具体做法是定义一个绑定了subcomponent builder的module,再将该module添加到注入你Applicationa的component中。
@Module(subcomponents = YourActivitySubcomponent.class)
abstract class YourActivityModule {
@Binds
@IntoMap
@ActivityKey(YourActivity.class)
abstract AndroidInjector.Factory extends Activity>
bindYourActivityInjectorFactory(YourActivitySubcomponent.Builder builder);
}
@Component(modules = {..., YourActivityModule.class})
interface YourApplicationComponent {}
Pro-tip:如果你的Subcomponent和它的builder没有其他方法或者supertypes,你可以使用ContributesAndroidInjector去自动生成上面两个步骤中的代码。添加一个抽象module并返回你的activity,并用@ContributesAndroidInjector,然后声明你想要安装到subcomponent中的modules,如果这个subcomponent需要scopes,在该方法中声明注释。
@ActivityScope
@ContributesAndroidInjector(modules = { /* modules to install into the subcomponent */ })
abstract YourActivity contributeYourActivityInjector();
4.让你的Application实现HasActivityInjector并且@Inject一个DispatchingAndroidInjector
public class YourApplication extends Application implements HasActivityInjector {
@Inject DispatchingAndroidInjector dispatchingActivityInjector;
@Override
public void onCreate() {
super.onCreate();
DaggerYourApplicationComponent.create()
.inject(this);
}
@Override
public AndroidInjector activityInjector() {
return dispatchingActivityInjector;
}
}
5.在你的Activity.onCreate()方法中在调用super.onCreate()方法前调用AndroidInjection.inject(this)方法
public class YourActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
}
}
6.完成
那么它是怎么工作的呢?
AndroidInjection.inject()得到了来自Application的DispatchingAndroidInjector
注入Fragment对象
注入一个Fragment和注入一个Activity一样简单。用同样的方法定义你的subcomponent,用Fragment.@FragmentKey和HasFragmentInjector
类型代替Activity.@ActivityKey和HasActivityInjector
用在onAttach()注入Fragments代替在onCreate()中的注入。
和在Activitys中定义modules不同,你有在何时为Fragments安装modules的选择。你可以让你的Fragment 成为另一个Fragment component,一个Activity component或者Application component的subcomponent。它取决于你的Fragment需要绑定哪个。在决定component位置后,让相应的类型(Activity)实现HasFragmentInjector。比分说,如果你的Fragment需要绑定YourActivitySubcomponent,你的代码会像这个样子:
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 {
@Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder {}
}
@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 { ... }
基本框架类型
Dagger2提供了DaggerActivity DaggerFragment 和 DaggerApplication这些基本框架类型,实现了HasActivityInjector/HasFragment以及调用AndroidInjection.inject().
以下类型也包括在内:
-
DaggerService
和DaggerIntentService
DaggerBroadcastReceiver
DaggerContentProvider
注意: DaggerBroadcastReceiver
只能在 BroadcastReceiver
注册时使用AndroidManifest.xml
。当 BroadcastReceiver
在你自己的代码中创建时,更喜欢构造器注入。
支持库
对于Android支持库的用户,dagger.android.support包中存在并行类型 。请注意,尽管支持Fragment用户必须绑定AndroidInjector.Factory extends android.support.v4.app.Fragment>,但AppCompat用户应继续执行,AndroidInjector.Factory extends Activity>而不是 extends AppCompatActivity>(或FragmentActivity)。
何时注射
只要有可能,构造方法注入是首选,因为它javac
确保在设置之前没有引用字段,这有助于避免NullPointerException
s。当需要成员注射(如上所述)时,倾向于尽早注射。为此,DaggerActivity
呼吁AndroidInjection.inject()
立即onCreate()
,调用之前 super.onCreate()
和DaggerFragment
做同样的onAttach()
,这也防止了矛盾,如果Fragment
重新连接。
AndroidInjection.inject()
在之前调用是非常重要super.onCreate()
的Activity
,因为调用在配置更改期间从先前的活动实例中super
附加Fragment
s,而这又会注入 Fragment
s。为了使Fragment
注射成功,Activity
必须已经注射。对于ErrorProne的用户来说,调用AndroidInjection.inject()
之后会出现编译器错误super.onCreate()
。
以上内容来自dagger2官网中的详解介绍。
更具体的参考了google的官方demo后,有了这么几个小结。
1.让Activity、Fragment和Application继承Dagger2提供的基本类型可以省去步骤4和5
2.由于Activity和Fragment在实现注入的时候,子组件及其构建器没有其他方法或supertypes,因此都可以使用Pro-tips中的方法自动生成代码。
3.在定制的Application中重写了applicationInjector()方法,该方法告诉Dagger如何制造我们的@Singleton Component。
4.为了进一步解耦,activity之间传值的时候,传值activity不用改,接收值的方法在接收activity的module中声明。Activity中接收值的变量需要用@Inject注释。