Dagger2是目前流行的一个依赖注入框架。使用它可以降低我们程序中类与类之间的耦合。类实例的创建,初始化,销毁及相互依赖都交由dagger2来管理。我们只需要专注于类本身的业务逻辑,提高我们编写程序的便利性。
传统MVP案例
MVP是我们项目中经常使用的一个应用框架。Model层负责具体的业务逻辑,View层负责界面的展示,Presenter层负责协调Model层与View层,通过调用Model层的业务方法,更新View层的界面展示。现在假如我们由这样一个需求:要求我们获取一段信息在界面上展示。应用MVP框架,我们可以这样实现:
/**
* 定义一个View层的统一接口
*/
public interface IView {
void updateUI(String text);
}
/**
* View层,负责界面的展示
*/
public class TestActivity extends AppCompatActivity implements IView {
TestPresent mPresent;//Present层实例
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
mPresent=new TestPresent(this);//创建Present层的实例
mPresent.updateUI();//调用Present层的更新UI的方法
}
@Override
public void updateUI(String text) {
((TextView)findViewById(R.id.textview)).setText(text);
}
}
/**
* Present类,调用Model层的业务方法,更新View层的界面展示
*/
public class TestPresent {
IView mView;//View层实例
TestModel mModel;//Model层实例
//构造方法,传入View层的实例
public TestPresent(IView view){
this.mView=view;
this.mModel=new TestModel();//创建Model层的实例
}
//更新UI的方法
public void updateUI(){
mView.updateUI(mModel.getText());//调用Model层是业务逻辑,更新View层的界面展示
}
}
/**
* Model类,实现具体的业务逻辑
*/
public class TestModel {
public TestModel(){
}
//返回需要展示的信息
public String getText(){
return "Dagger2应用实践...";
}
}
通过以上代码,我们顺利的通过MVP框架实现了我们的需求,代码模块间分工明确,各模块只负责自己本模块的工作。但是这里有一个问题,模块之间相互依赖,一个模块都要依赖其它的模块才能完成实际的功能。根据单一职责原则,一个内聚性高的类,应该只做自己类本身的工作,在需要使用其它的类时,我们只要调用类实例的方法就可以了,实例的创建,初始化,销毁等工作,则不应该由本类负责。通过依赖注入框架,我们就可以只关注类本身的工作,依赖类的创建,初始化,销毁等工作,统统交给依赖注入框架来处理。
Dagger2案例
Dagger2是通过apt根据注解在编译时生成额外的代码实现依赖注入,所以要使用dagger2,首先我们需要在build.gradle(Project:xxx)中配置apt插件:
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
//添加apt插件
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
在build.gradle(Module:app)中添加添加dagger2依赖:
apply plugin: 'com.android.application'
//添加如下代码,应用apt插件
apply plugin: 'com.neenbedankt.android-apt'
...
dependencies {
...
//dagger2
compile 'com.google.dagger:dagger:2.4'
apt 'com.google.dagger:dagger-compiler:2.4'
//java注解
compile 'org.glassfish:javax.annotation:10.0-b28'
}
使用Dagger2注解修改各个类:
/**
* 定义一个View层的统一接口
* View接口保持不变
*/
public interface IView {
void updateUI(String text);
}
/**
* View层,负责界面的展示
*/
public class TestActivity extends AppCompatActivity implements IView{
//当一个成员变量被@Inject注解修饰,并且它的类型构造函数也被@Inject注解修饰,dagger2就会自动实例化该成员类型,并注入到该成员变量
@Inject
TestPresent mPresent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
DaggerTestComponent.builder().testModule(new TestModule(this)).build().inject(this);//@Component负责连接起@Inject和@Module注解
mPresent.updateUI();
}
@Override
public void updateUI(String text) {
((TextView)findViewById(R.id.textview)).setText(text);
}
}
/**
* Present类,调用Model层的业务方法,更新View层的界面展示
*/
public class TestPresent {
IView mView;
@Inject
TestModel mModel;//Dagger2遇到@Inject标记的成员属性,就会去查看该成员类的构造函数,如果构造函数也被@Inject标记,则会自动初始化,完成依赖注入。
//TestPresent的构造函数也被@Inject注解修饰
@Inject
public TestPresent(IView view){
this.mView=view;
}
public void updateUI(){
mView.updateUI(mModel.getText());
}
}
/**
* Model类,实现具体的业务逻辑
*/
public class TestModel {
//构造函数用@Inject修饰
@Inject
public TestModel(){
}
public String getText(){
return "Dagger2应用实践...";
}
}
/**
* Module类提供那些没有构造函数的类的依赖,如第三方类库,系统类,接口类
*/
@Module
public class TestModule {
private IView mView;
public TestModule(IView iView){
this.mView=iView;
}
//@Provides注解的方法,提供IView类的依赖。
@Provides
public IView provideIView(){
return this.mView;
}
}
/**
*Component必须是一个接口类或者抽象
*/
@Component(modules = TestModule.class)
public interface TestComponent {
void inject(TestActivity testActivity);
}
总结:
看到这里小伙伴们大概已经知道如何使用dagger2了。但对于代码为何这样写,dagger2内部是怎么帮我们实现各个类间的依赖注入的还不是很清楚。接下来,我们就进入到dagger2为我们生成类的源码中看看,dagger2分别为我们实现了那些类,这些类之间是如何协作来帮助我们实现依赖注入的。
Dagger2原理分析
DaggerTestComponent.builder().testModule(new TestModule(this)).build().inject(this);//@Component连接起@Inject和@Module的关键
DaggerTestComponent,这是什么鬼,我们好像没有定义过这个类啊,别急,这个dagger2根据@Component注解帮我们生成的类,我们进去看看它具体做了什么工作。
DaggerTestComponent源码:
/**
1. dagger2根据@Component注解帮我们生成的类,实现我们定义的TestComponent接口
*/
public final class DaggerTestComponent implements TestComponent {
private MembersInjector testPresentMembersInjector;//负责注入TestPresent中被@Inject注解修饰的的成员变量的依赖。dagger2会为TestPresent生成一个TestPresent_MembersInjector类,专门负责TestPresent中@Inject注解的依赖注入
private Provider provideIViewProvider;//负责注入TestPresent中没有构造函数的成员变量的依赖。dagger2会依据@Component中传入的modules值(示例中为TestModule),为Module类中@Provides修饰的方法(示例中为provideIView)提供一个TestModule_ProvideIViewFactory类
private Provider testPresentProvider;//提供TestActivity中TestPresent类型的依赖
private MembersInjector testActivityMembersInjector;//负责注入TestActivity中@Inject修饰的成员变量
private DaggerTestComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.testPresentMembersInjector =
TestPresent_MembersInjector.create(TestModel_Factory.create());//创建TestModel_Factory实例,再根据生成的TestModel_Factory实例创建TestPresent_MembersInjector的实例
this.provideIViewProvider = TestModule_ProvideIViewFactory.create(builder.testModule);//通过传入的TestModule实例创建TestModule_ProvideIViewFactory的实例
this.testPresentProvider =
TestPresent_Factory.create(testPresentMembersInjector, provideIViewProvider);//根据testPresentMembersInjector和provideIViewProvider创建TestPresent_Factory的实例
this.testActivityMembersInjector = TestActivity_MembersInjector.create(testPresentProvider);//根据testPresentProvider创建TestActivity_MembersInjector的实例
}
@Override
public void inject(TestActivity testActivity) {
testActivityMembersInjector.injectMembers(testActivity);//调用testActivityMembersInjector的injectMembers方法为TestActivity提供依赖注入
}
public static final class Builder {
private TestModule testModule;
private Builder() {}
public TestComponent build() {
if (testModule == null) {
throw new IllegalStateException(TestModule.class.getCanonicalName() + " must be set");
}
return new DaggerTestComponent(this);
}
//传入TestModule的实例
public Builder testModule(TestModule testModule) {
this.testModule = Preconditions.checkNotNull(testModule);
return this;
}
}
}
可以看到,dagger2为TestActivity实现依赖注入的步骤大概如下:
此时,dagger2已经通过@Component关联起了@Inject和@Module注解。但是具体是怎么注入的我们还不是很清楚,我们看到inject方法中调用testActivityMembersInjector的injectMembers()方法完成了对TestActivity的依赖注入,我们再看TestActivity_MembersInjector的源码:
/**
* dagger2根据TestActivity中的@Inject注解生成的成员注入类
*/
public final class TestActivity_MembersInjector implements MembersInjector {
private final Provider mPresentProvider;
public TestActivity_MembersInjector(Provider mPresentProvider) {
assert mPresentProvider != null;
this.mPresentProvider = mPresentProvider;//将create方法中传入的mPresentProvider赋值mPresentProvider
}
//mPresentProvider即为DaggerTestComponent中创建的TestPresent_Factory的实例testPresentProvider
public static MembersInjector create(Provider mPresentProvider) {
return new TestActivity_MembersInjector(mPresentProvider);
}
//依赖注入方法,在DaggerTestComponent的inject方法中被调用
@Override
public void injectMembers(TestActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.mPresent = mPresentProvider.get();//通过mPresentProvider的get方法获取到TestPresent的实例并赋值给TestActivity中的mPresent
}
public static void injectMPresent(TestActivity instance, Provider mPresentProvider) {
instance.mPresent = mPresentProvider.get();
}
}
可以看到,上面代码中是通过mPresentProvider(TestPresent_Factory的实例)的get方法获取到TestPresent的实例并复制给TestActivity中的mPresent,TestPresent_Factory的源码:
/**
* dagger2生成的TestPresent工厂类
*/
public final class TestPresent_Factory implements Factory<TestPresent> {
private final MembersInjector testPresentMembersInjector;//提供TestPresent中@Inject注解修饰的成员变量的依赖
private final Provider viewProvider;//提供TestPresent中不能被@Inject修饰的成员变量(变量类型没有构造函数或构造函数上无法加@Inject注解)的依赖
public TestPresent_Factory(
MembersInjector testPresentMembersInjector, Provider viewProvider) {
assert testPresentMembersInjector != null;
this.testPresentMembersInjector = testPresentMembersInjector;
assert viewProvider != null;
this.viewProvider = viewProvider;
}
@Override
public TestPresent get() {
//首先根据传入的viewProvider中的get方法获取到IView实例,创建TestPresent的实例,
// 再通过MemberInjectors.injecMembers方法,为创建的TestPreset实例注入@Inject修饰的成员变量(mModule)
//然后返回创建的TestPresent实例
return MembersInjectors.injectMembers(
testPresentMembersInjector, new TestPresent(viewProvider.get()));
}
//此处传入的testPresentMemberInjector即为DaggerTestComponent中创建的TestPresent_MembersInjector的实例
//viewProvider即为DaggerTestComponent中创建的TestModule_ProvideIViewFactory的实例
public static Factory create(
MembersInjector testPresentMembersInjector, Provider viewProvider) {
return new TestPresent_Factory(testPresentMembersInjector, viewProvider);
}
}
TestPresent_Factory中通过viewProvider的get方法获取到IView的实例,此处的viewProvider即为DaggerTestComponent中传入的TestModule_ProvideIViewFactory实例:
/**
* dagger2为@Module修饰的类中的每个@Provides修饰的方法生成的类
*/
public final class TestModule_ProvideIViewFactory implements Factory<IView> {
private final TestModule module;
public TestModule_ProvideIViewFactory(TestModule module) {
assert module != null;
this.module = module;
}
@Override
public IView get() {
return Preconditions.checkNotNull(
module.provideIView(), "Cannot return null from a non-@Nullable @Provides method");//通过传入的TestModule实例的provideIView方法获取IView的实例并返回
}
//此处的module即为TestActivity中通过DaggerTestComponet.Builder().testModule()方法传入的TestModule实例
public static Factory create(TestModule module) {
return new TestModule_ProvideIViewFactory(module);
}
}
TestPresent_Factory中通过MembersInjectors中的injectMembers方法,为创建的TestPresent注入@Inject修饰的成员变量(mModel)的依赖。MembersInjectors的源码:
public final class MembersInjectors {
public static T injectMembers(MembersInjector membersInjector, T instance) {
membersInjector.injectMembers(instance);//membersInjector为DaggerTestComponent中传入的TestPresent_MembersInjector的实例testPresentMembersInjector,实际上调用的是TestPresent_MembersInjector的injectMembers()方法
return instance;
}
}
TestPresent_MembersInjector的源码:
public final class TestPresent_MembersInjector implements MembersInjector {
private final Provider mModelProvider;
public TestPresent_MembersInjector(Provider mModelProvider) {
assert mModelProvider != null;
this.mModelProvider = mModelProvider;
}
public static MembersInjector create(Provider mModelProvider) {
//mModelProvider为DaggerTestComponent中传入的TestModel_Factory的实例
return new TestPresent_MembersInjector(mModelProvider);
}
@Override
public void injectMembers(TestPresent instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.mModel = mModelProvider.get();//通过mModelProvider的get方法获取到TestModel的实例并赋值给TestPresent实例中的mModel。
}
public static void injectMModel(TestPresent instance, Provider mModelProvider) {
instance.mModel = mModelProvider.get();
}
}
TestModel_Factory源码:
public enum TestModel_Factory implements Factory {
INSTANCE;
@Override
public TestModel get() {
return new TestModel();//返回TestModel的实例
}
public static Factory create() {
return INSTANCE;//返回TestModel_Factory的实例
}
}
至此,我们完整分析了Dagger2为我们实现依赖注入的全过程,相信大家对Dagger2为我们实现依赖注入的原理有了一定的了解。有什么不解的欢迎大家在评论区给我留言,我会尽量作答。