一看就会,Dagger原理简单分析

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()里会用到。

我们单独把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了。

Android的技术讨论Q群:947460837

你可能感兴趣的:(一看就会,Dagger原理简单分析)