Dagger2是一款依赖注入框架,相比于黄油刀,Dagger2的入门难度系数更大。如果你还没有使用过Dagger2,赶紧去尝试一下吧。
首先说一下Dagger2,可以帮我们干哪些活。使用过MVP开发的老铁们都知道,Activity持有Presenter层的实例,也就是说 ,我们需要去实例化这个Presenter,而Presenter持有了View层接口的实例。这样程序之间耦合性非常严重,我们希望,把某个类的实例化过程放到一个容器中,当前的Activity不需要去管理他的实例化过程,说的直白点,不用我们手动的去new 这个对象了。我们仔细想想,这样做有什么好处,假设程序中有很多的地方用到了这个Presenter,有朝一日,我们发现,Presenter设计的不够完美,构造方法需要改动,这样一来可就麻烦了,所有用到的Presenter的地方,都需要去进行改动。这个时候,Dagger派上用场了
常规写法:
public class MainActivity extends AppCompatActivity implements IView{
public MainPresenter mainPresenter;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.tv_1);
// 实例化Presenter
mainPresenter = new MainPresenter(this);
mainPresenter.getData();
}
@Override
public void getString(String str) {
// Iview 接口的回调
textView.setText(str);
}
}
public interface IView {
void getString(String str);
}
public class MainPresenter {
IView iView;
MainPresenter(IView iView) {
this.iView = iView;
}
// 提供给 Activity层调用
public void getData() {
// dosomething:假设通过Model层获取到数据之后,回调给IView。
iView.getString("hello java");
}
}
以上就是最简单的MVP的写法(没有写Model层)。
使用Dagger怎么写呢?
public class MainActivity extends AppCompatActivity implements IView{
@Inject
public MainPresenter mainPresenter;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.tv_1);
DaggerMainComponent.builder()
.mainViewModule(new MainViewModule(this))
.build()
.inject(this);
mainPresenter.getData();
}
@Override
public void getString(String str) {
// TODO
textView.setText(str);
}
}
public interface IView {
void getString(String str);
}
public class MainPresenter {
IView iView;
@Inject
MainPresenter(IView iView) {
this.iView = iView;
}
public void getData() {
// dosomething:假设通过Model层获取到数据之后,回调给IView。
iView.getString("hello java");
}
}
相比于常规写法,我们没有在MainActivity里进行new MainPresenter(this)操作,而是使用了 @Inject 来标注了我们想要实例化的类以及标注它的构造函数。使用@Inject相当于做了个"记号",告诉Dagger,我想要这个类的实例,麻烦你去帮我做一下实例化操作。
这里再贴一下,Component和Module的代码:
### MainComponent
@Component (modules = {MainViewModule.class})
public interface MainComponent {
void inject(MainActivity activity);
}
////////////////////////////////////////////
### MainViewModule
@Module
public class MainViewModule {
IView iView;
public MainViewModule(IView iView) {
this.iView = iView;
}
@Provides
IView create() {
return iView;
}
}
以上是Dagger2很简单的使用,当然这也不是我们今天所要关心的,今天的主题是,Dagger2是怎么帮我们实现了 new MainPresenter(this) 这个操作的,内部的逻辑是怎样的呢?
简单分析原理
Dagger2自动生成代码的原理是 通过apt插件在编译时期生成相应的注入代码,接下来我们就一个一个的分析。
1.MainPresenter与MainPresenter_Factory
我们用 @Inject 标注了MainPresenter 以及他的 构造函数,然后我们Rebuild Project一下,会在app/build/generated/source/apt/debug/包名/ 下生成一个 类 MainPresenter_Factory,这里贴一下 MainPresenter与MainPresenter_Factory 的代码:
### MainPresenter_Factory类
public final class MainPresenter_Factory implements Factory {
private final Provider iViewProvider;
public MainPresenter_Factory(Provider iViewProvider) {
assert iViewProvider != null;
this.iViewProvider = iViewProvider;
}
@Override
public MainPresenter get() {
return new MainPresenter(iViewProvider.get());
}
public static Factory create(Provider iViewProvider) {
return new MainPresenter_Factory(iViewProvider);
}
}
### MainPresenter类
public class MainPresenter {
IView iView;
@Inject
MainPresenter(IView iView) {
this.iView = iView;
}
public void getData() {
// dosomething:假设通过Model层获取到数据之后,回调给IView。
iView.getString("hello java");
}
}
我们重点看MainPresenter_Factory 的get()方法,返回类型是 MainPresenter,get()方法内部实际上是去new了一个MainPresenter,传入的参数是iViewProvider.get()。我们不禁会想,Dagger2 是不是在这里帮我们实例化MainPresenter的?答案是肯定的
iViewProvider是一个Provider类型,泛型参数是我们 new MainPresenter()所需要的IView。iViewProvider是在MainPresenter_Factory 的构造函数进行初始化的。
public interface Provider {
T get();
}
create()返回返回一个 MainPresenter_Factory实例,好像没什么好说的,暂时先放一边。
MainPresenter_Factory类看完了,还是一头雾水,我们知道get()方法会返回一个我们所需要的MainPresenter实例,但是我们不清楚 get()是被谁调用的,以及iViewProvider.get() 是谁提供的呢??
思考: MainPresenter 的构造函数中传入的参数是IView,而IView是接口类型,Dagger明确规定,不能使用@Inject来标注接口和第三方库,碰到这种情况,需要使用到Module,所以我们有理由相信,iViewProvider.get() 是由MainViewModule提供的
带着这两个疑问看下文!!!
2.MainViewModule与MainViewModule_CreateFactory
public final class MainViewModule_CreateFactory implements Factory {
private final MainViewModule module;
public MainViewModule_CreateFactory(MainViewModule module) {
assert module != null;
this.module = module;
}
@Override
public IView get() {
IView provided = module.create();
if (provided == null) {
throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
}
return provided;
}
public static Factory create(MainViewModule module) {
return new MainViewModule_CreateFactory(module);
}
}
////////////////////////////////////////////
@Module
public class MainViewModule {
IView iView;
public MainViewModule(IView iView) {
this.iView = iView;
}
@Provides
IView create() {
return iView;
}
}
重点看看 MainViewModule_CreateFactory的get()方法,返回IView,这不就是我们new MainPresenter()所需要的参数吗!但是到这里我们还是不能确定,iViewProvider.get() 是由MainViewModule提供的!
我们虽然找到了MainViewModule_CreateFactory,也看到了它的get()方法的返回值就是我们 new MainPresenter()所需要的那个参数,但是,我们没有找到证据,iViewProvider.get() 就是由MainViewModule提供的。
正当我一筹莫展的时候,想起了之前网上看博客大牛们说,Component的作用像一个桥梁,负责把@Inject和Module的提供的实例一起注入到目标类中.. 莫非,我要找的答案在MainComponent以及它生成的类中吗?
答案也是肯定的!!!
3.MainComponent与DaggerMainComponent
public final class DaggerMainComponent implements MainComponent {
private Provider createProvider;
private Provider mainPresenterProvider;
private MembersInjector mainActivityMembersInjector;
private DaggerMainComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
private void initialize(final Builder builder) {
this.createProvider = MainViewModule_CreateFactory.create(builder.mainViewModule);
this.mainPresenterProvider = MainPresenter_Factory.create(createProvider);
this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), mainPresenterProvider);
}
@Override
public void inject(MainActivity activity) {
mainActivityMembersInjector.injectMembers(activity);
}
public static final class Builder {
private MainViewModule mainViewModule;
private Builder() {
}
public MainComponent build() {
if (mainViewModule == null) {
throw new IllegalStateException("mainViewModule must be set");
}
return new DaggerMainComponent(this);
}
public Builder mainViewModule(MainViewModule mainViewModule) {
if (mainViewModule == null) {
throw new NullPointerException("mainViewModule");
}
this.mainViewModule = mainViewModule;
return this;
}
}
}
//////////////////////////////////
@Component (modules = {MainViewModule.class})
public interface MainComponent {
void inject(MainActivity activity);
}
DaggerMainComponent实现了MainComponent接口。在构造函数里调用了initialize(),initialize()内部做了初始化操作。首先创造了MainViewModule_CreateFactory实例,接着把这个实例作为参数去生成MainPresenter_Factory实例,这不就是我们在第二步一直困惑的地方吗,终于找到证据了,哈哈。 MainPresent实例所需要的依赖由MainViewModule_CreateFactory提供。最后一步是生成MainActivity_MembersInjector实例,我猜测是MainActivity的注入类。
内部类Builder主要是做了创建Module以及自身的实例,不是重点。
我们大概捋一捋,我们所需要的MainPresenter实例由MainPresenter_Factory##get()创建,而创建MainPresent实例所需要的依赖由MainViewModule_CreateFactory提供。但是,在步骤1里,我们还是有个疑问没解决,MainPresenter_Factory##get()是被谁调用的呢?
重点看看DaggerMainComponent###inject()方法,方法内部调用的是 mainActivityMembersInjector.injectMembers(activity),将MainActivity注入到MainActivity_MembersInjector类中。
public final class MainActivity_MembersInjector implements MembersInjector {
private final MembersInjector supertypeInjector;
private final Provider mainPresenterProvider;
public MainActivity_MembersInjector(MembersInjector supertypeInjector, Provider mainPresenterProvider) {
assert supertypeInjector != null;
this.supertypeInjector = supertypeInjector;
assert mainPresenterProvider != null;
this.mainPresenterProvider = mainPresenterProvider;
}
@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
supertypeInjector.injectMembers(instance);
instance.mainPresenter = mainPresenterProvider.get();
}
public static MembersInjector create(MembersInjector supertypeInjector, Provider mainPresenterProvider) {
return new MainActivity_MembersInjector(supertypeInjector, mainPresenterProvider);
}
}
MainActivity_MembersInjector构造函数里接收一个Provider
我们单独把injectMembers()拎出来:
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
supertypeInjector.injectMembers(instance);
instance.mainPresenter = mainPresenterProvider.get();
}
instance.mainPresenter = mainPresenterProvider.get();
看到这行代码的时候,所有的疑问都消除了,也就是说 上面的那个疑问:MainPresenter_Factory##get()是被谁调用的呢?? 它其实是在这里被调用的。
看到这里是不是有种 恍然大悟的感觉!mainPresenterProvider.get()也就是 Dagger2帮助我们生成的MainPresenter实例,刚开始我们还保持怀疑,mainPresenterProvider.get()得到到实例是不是指向了我们MainActivity的那个实例呢? 看到这里,才真正的明白了,将MainPresenter_Factory中创建好的MainPresenter实例赋值给instance(MainActivity)的成员mainPresenter,这样我们用@Inject标注的mainPresenter就得到了实例化。
做个小结吧,Module的作用是 提供依赖,像我们的例子中的:
MainPresenter(IView iView) {
this.iView = iView;
}
这个IView 实例就是由Module去提供的,而Component的作用像一个桥梁,负责把@Inject和Module的提供的实例一起注入到目标类中,像这个例子,目标类就是MainActivity了。