一、简介
Dagger2是一个使用广泛的依赖注入框架,由大名鼎鼎的Square公司最开始开发,目前由Google公司维护。
初期可能入手难度较大,而且对于小型的项目的话并没有体现其真正的价值,反而增加了不少代码量,是否使用可以这个可以根据喜好和实际的项目选择。
1)按照Google官方示例代码,Dagger2主要包括几个核心的类需要定义
XXContract 接口类,提供了View和Presenter的接口定义
UI层(Activity、Fragment等)实现View的接口,提供Presenter所需要的数据,并实现更新UI的操作
XXPresenter:实现Presenter接口 ,处理数据并通过View更新UI,是整个数据处理的核心
XXPresenterModule:为XXPresenter提供构造需要的参数
XXComponent:注入组件接口,编译时自动生成DaggerXXComponent,是注入的核心部分,可以是单例的或者作为其他组件的子组件使用。
2)主要注解
@Inject:需要注入的成员或方法的注解
@Module:提供依赖,即我们常用的new出来的实例
@Provides:Module中提供依赖的方法注解
@Component:注入的纽带,关联需要注入的@Inject和@Module依赖
@Scope:作用域声明,如@Singleton即是一个默认的声明
二、原理及示例
下面来结合一个简单的例子来讲解一下各个类实现以及Dagger注入的原理
1)MainContract定义了两个接口Presenter和View。View通过getCar提供当前的车辆信息,还有一个showCar方法用来展示当前的车辆信息
public interface MainContract {
interface Presenter {
void decorCar();
}
interface View {
Car getCar();
void showCar(Car car);
}
}
2)MainPresenter
public class MainPresenter implements MainContract.Presenter {
public static final String TAG = MainPresenter.class.getSimpleName();
@Inject
Context mContext;
MainContract.View mView;
@Inject
public MainPresenter(Context context, MainContract.View mView) {
this.mContext = context;
this.mView = mView;
}
@Inject
public void init(Context context) {
Log.d(TAG, "MainPresenter Init() from inject.");
}
@Inject
public void init2() {
Log.d(TAG, "MainPresenter Init2() from inject.");
}
@Override
public void decorCar() {
Car car = mView.getCar();
String[] colors = {"GREEN", "YELLOW", "BLACK"};
car.setColor(colors[(int) (System.currentTimeMillis() % 3)]);
mView.showCar(car);
}
}
MainPresenter实现了MainContract.Presenter定义的接口,他拥有一个构造方法,持有需要操作的MainContract.View的引用,构造方法有个一个@Inject注解,表示需要通过注入的方式实例化。init和init2这方法@Inject注解,当注入完成后会调用该方法,当然也支持带参数的方法。
MainPresenter中需要通过@Inject注入的构造函数、成员和方法,这些成员或方法的参数需要由关联的MainPresenterModule提供参数,否则编译时会有错误。构造方法不允许多个注入。
... cannot be provided without an @Provides-annotated method.
3)MainPresenterModule
构造函数包括一个Context和一个MainContact.View,这两个成员通过@provides注解提供给MainPresenter注入使用。方法名字可以根据自己喜好命名,最好以provide开始表示提供该参数。
@Module
public class MainPresenterModule {
Context mContext;
MainContract.View mView;
public MainPresenterModule(Context context, MainContract.View view) {
this.mContext = context;
this.mView = view;
}
@Provides
public Context provideContext() {
return mContext;
}
@Provides
public MainContract.View provideMainContractView() {
return mView;
}
}
4)定义Component接口。
这里注解modules可以支持多个模块的注入,另外有@SubComponent用来在别的@Component中复用当前的Component。这里可以根据需要inject可以定义多个,用来注入到不同的控件中,或者返回Presenter的其他需要的数据。
@Component(modules = {MainPresenterModule.class, MainPresenterModule2.class})
public interface MainComponent {
void inject(MainActivity activity);
}
最后我们来实现XXContract.View的接口,为了方便,我们直接在MainActivity中实现。点击文本时,mPresenter重新装饰Car,并显示新的车辆的信息。
public class MainActivity extends AppCompatActivity implements MainContract.View {
public static final String TAG = MainActivity.class.getSimpleName();
@Inject
MainPresenter mPresenter = null;
Car mCar = new Car("BMW", "320Li", 300000f, "WHITE");
TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.text);
mTextView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPresenter.decorCar();
}
});
DaggerMainComponent.builder()
.mainPresenterModule(new MainPresenterModule(this.getApplicationContext(), this))
.build()
.inject(this);
}
@Override
public Car getCar() {
return mCar;
}
@Override
public void showCar(Car car) {
mTextView.setText(car.toString());
}
}
编译工程后,dagger会为我们自动生成如下一些类。
1)DaggerMainComponent
2)MainPresenterModule_ProvideContextFactory、MainPresenterModule_ProvideMainContractViewFactory
3)MainPresenter_MembersInjector
4)MainPresenter_Factory
5)MainActivity_MembersInjector
下面来仔细分析一下各个类
1)DaggerMainComponent
DaggerMainComponent是编译后自动生成的类,他实现了我们之前定义的接口MainComponent,源码如下
public final class DaggerMainComponent implements MainComponent {
private Provider<Context> provideContextProvider;
private MembersInjector<MainPresenter> mainPresenterMembersInjector;
private Provider<MainContract.View> provideMainContractViewProvider;
private Provider<MainPresenter> mainPresenterProvider;
private MembersInjector<MainActivity> mainActivityMembersInjector;
private DaggerMainComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.provideContextProvider =
MainPresenterModule_ProvideContextFactory.create(builder.mainPresenterModule);
this.mainPresenterMembersInjector =
MainPresenter_MembersInjector.create(provideContextProvider);
this.provideMainContractViewProvider =
MainPresenterModule_ProvideMainContractViewFactory.create(builder.mainPresenterModule);
this.mainPresenterProvider =
MainPresenter_Factory.create(
mainPresenterMembersInjector, provideContextProvider, provideMainContractViewProvider);
this.mainActivityMembersInjector = MainActivity_MembersInjector.create(mainPresenterProvider);
}
@Override
public void inject(MainActivity activity) {
mainActivityMembersInjector.injectMembers(activity);
}
public static final class Builder {
private MainPresenterModule mainPresenterModule;
private Builder() {}
public MainComponent build() {
if (mainPresenterModule == null) {
throw new IllegalStateException(
MainPresenterModule.class.getCanonicalName() + " must be set");
}
return new DaggerMainComponent(this);
}
public Builder mainPresenterModule(MainPresenterModule mainPresenterModule) {
this.mainPresenterModule = Preconditions.checkNotNull(mainPresenterModule);
return this;
}
/**
* @deprecated This module is declared, but an instance is not used in the component. This method is a no-op. For more, see https://google.github.io/dagger/unused-modules.
*/
@Deprecated
public Builder mainPresenterModule2(MainPresenterModule2 mainPresenterModule2) {
Preconditions.checkNotNull(mainPresenterModule2);
return this;
}
}
}
整个注入过程开始如下:
i) DaggerMainComponent的静态方法builder()创建一个DaggerMainComponent.Builder的实例。
ii) mainPresenterModule将MainPresenterModule对象设置到Builder中,MainPresenterModule有两个成员Context和MainContract.View,为MainPresenter的注入提供参数。 DaggerMainComponent根据modules生成对应的设置参数的方法,并且是链式的,方便调用。
iii) build()方法创建一个DaggerMainComponent的实例,并把自己传递过去以供初始化。
iiii) 最后通过inject方法注入到对于的组件中。
DaggerMainComponent.builder()
.mainPresenterModule(new MainPresenterModule(this.getApplicationContext(), this))
.build()
.inject(this);
2) MainPresenterModule_ProvideContextFactory等
Module中每个注解为@Provides的方法都会生成一个对应的Factory类,Factory继承自Provider,get()方法返回需要的数据。如MainPresenterModule_ProvideContextFactory类,他有一个MainPresenterModule的成员,get方法通过MainPresenterModule的provideContext方法返回一个Context。
public final class MainPresenterModule_ProvideContextFactory implements Factory<Context> {
private final MainPresenterModule module;
public MainPresenterModule_ProvideContextFactory(MainPresenterModule module) {
assert module != null;
this.module = module;
}
@Override
public Context get() {
return Preconditions.checkNotNull(
module.provideContext(), "Cannot return null from a non-@Nullable @Provides method");
}
public static Factory<Context> create(MainPresenterModule module) {
return new MainPresenterModule_ProvideContextFactory(module);
}
}
3) MainPresenter_MembersInjector
MainPresenter_MembersInjector 主要用来注入成员变量和方法,他的构造函数的参数是用到的各个参数对应的的Provider,这些Provider为注入提供所需的数据。
public final class MainPresenter_MembersInjector implements MembersInjector<MainPresenter> {
private final Provider<Context> mContextAndContextProvider;
public MainPresenter_MembersInjector(Provider<Context> mContextAndContextProvider) {
assert mContextAndContextProvider != null;
this.mContextAndContextProvider = mContextAndContextProvider;
}
public static MembersInjector<MainPresenter> create(
Provider<Context> mContextAndContextProvider) {
return new MainPresenter_MembersInjector(mContextAndContextProvider);
}
@Override
public void injectMembers(MainPresenter instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.mContext = mContextAndContextProvider.get();
instance.init(mContextAndContextProvider.get());
instance.init2();
}
public static void injectMContext(MainPresenter instance, Provider<Context> mContextProvider) {
instance.mContext = mContextProvider.get();
}
}
4)MainPresenter_Factory
MainPresenter_Factory是一个用于创建MainPresenter的工厂类,他的构造参数是一个MainPresenter_MembersInjector的实例,以及MainPresenter需要@Inject的构造方法用到的参数对应的Provider。MainPresenter的构造方法有两个参数Context和MainContact.View,因此这里需要他们对应的Provider作为参数。
注意构造方法不允许多个注入public final class MainPresenter_Factory implements Factory<MainPresenter> {
private final MembersInjector<MainPresenter> mainPresenterMembersInjector;
private final Provider<Context> contextProvider;
private final Provider<MainContract.View> mViewProvider;
public MainPresenter_Factory(
MembersInjector<MainPresenter> mainPresenterMembersInjector,
Provider<Context> contextProvider,
Provider<MainContract.View> mViewProvider) {
assert mainPresenterMembersInjector != null;
this.mainPresenterMembersInjector = mainPresenterMembersInjector;
assert contextProvider != null;
this.contextProvider = contextProvider;
assert mViewProvider != null;
this.mViewProvider = mViewProvider;
}
@Override
public MainPresenter get() {
return MembersInjectors.injectMembers(
mainPresenterMembersInjector,
new MainPresenter(contextProvider.get(), mViewProvider.get()));
}
public static Factory<MainPresenter> create(
MembersInjector<MainPresenter> mainPresenterMembersInjector,
Provider<Context> contextProvider,
Provider<MainContract.View> mViewProvider) {
return new MainPresenter_Factory(mainPresenterMembersInjector, contextProvider, mViewProvider);
}
}
这里的get()方法最终调用如下代码,执行MainPresenter_MembersInjector的injectMembers方法,注入成员变量和函数,并最终返回一个MainPresenter的实例。
public static <T> T injectMembers(MembersInjector<T> membersInjector, T instance) {
membersInjector.injectMembers(instance);
return instance;
}
5)MainActivity_MembersInjector
所有上述变量都是为MainActivity_MembersInjector做准备的,他的工厂方法需要一个MainPresenter_Factory的实例作为参数。public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
private final Provider<MainPresenter> mPresenterProvider;
public MainActivity_MembersInjector(Provider<MainPresenter> mPresenterProvider) {
assert mPresenterProvider != null;
this.mPresenterProvider = mPresenterProvider;
}
public static MembersInjector<MainActivity> create(Provider<MainPresenter> mPresenterProvider) {
return new MainActivity_MembersInjector(mPresenterProvider);
}
@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.mPresenter = mPresenterProvider.get();
}
public static void injectMPresenter(
MainActivity instance, Provider<MainPresenter> mPresenterProvider) {
instance.mPresenter = mPresenterProvider.get();
}
}
当DaggerMainComponent的注入方法inject被调用时,mainActivityMembersInjector(MainActivity_MembersInjector)的injectMembers将执行,mPresenterProvider(MainPresenter_Factory)的get()方法注入MainPresenter成员变量及方法,并返回MainPresenter的实例,然后MainActivity的mPrestener被设置为返回的MainPresenter实例,这样整个注入就完成了。
三、总结
上面介绍的只是一个简单的注入示例,如@Singleton 、@SubComponent等等一些复杂的使用暂时不做展开。
这里有几个注意的地方:
1)注入的成员不能是private的。错误: Dagger does not support injection into private fields.
这个很好理解,注入都是通过直接赋值设置参数,private修饰成员不能直接访问
3)XXPresenterModule必须定义@Provides方法给XXPresenter提供必须的参数。错误:xx cannot be provided without an @Provides-annotated method.
2)XXPresenter的构造函数的注入只支持一个。错误:Types may only contain one @Inject constructor.