Dagger2原理解析

一、简介

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注解,表示需要通过注入的方式实例化。initinit2这方法@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_MembersInjectorinjectMembers方法,注入成员变量和函数,并最终返回一个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.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值