2.基于Dagger2.38.1版本全面理解注解-android

455 阅读4分钟

前言

Dagger2当前版本有android和compiler、hilt三个板块。这里对android板块下的注解解说,该板块下主要针对@AndroidInjectionKey和@ClassKey两个注解、@ContributesAndroidInjector注解的处理。

换句话说如果项目中不存在使用AndroidInjectionKey、ClassKey和ContributesAndroidInjector注解,不要轻易将当前android板块引入到项目中。

@AndroidInjectionKey 和 @ClassKey

@AndroidInjectionKey和@ClassKey本身就是使用@MapKey注解修饰的注解。

先回一下@MapKey注解规则:

  1. 如果MapKey.unwrapValue() = true的情况下(默认情况下就是true),被修饰的注解有且仅有一个方法,并且该方法返回类型不能是数组类型;
  • e.g.ClassKey注解
  1. 如果MapKey.unwrapValue() = false,那就麻烦了,被修饰的注解方法不但不限制,而且我们的项目中必须引入了com.google.auto.value.AutoAnnotation依赖,这是什么骚操作???
  • (1)引入AutoAnnotation的目的是对MapKey修饰的注解的所有方法返回类型作为变量生成一个新的类T,相当于MapKey.unwrapValue() = true的情况下的 @MapKey(T.class);

  • (2)所以MapKey.unwrapValue() = false可以使用MapKey.unwrapValue() = true替代,而且MapKey.unwrapValue() = true更容易理解、实现也更加稳健。非必要不要使用MapKey.unwrapValue() = false

  1. @MapKey修饰的注解和@IntoMap是情侣关系,必须在一起!!!

AndroidInjectionKey注解只能修饰方法,ClassKey注解可以修饰方法和变量。

我们仅仅针对@AndroidInjectionKey或@ClassKey修饰的方法做校验工作,校验规则如下:

  1. @AndroidInjectionKey 和 @ClassKey 必须满足@MapKey注解规则;

  2. 如果方法使用了@AndroidInjectionKey或@ClassKey修饰,那么当前方法不能使用@Qualifier修饰的注解修饰;

  3. 使用@AndroidInjectionKey或@ClassKey修饰修饰的方法返回类型如果不是AndroidInjector.Factory及其子类,不需要继续校验了,该方法直接被忽略;

  4. 如果该方法使用了@Scope注解修饰的注解修饰,该方法必须使用@SuppressWarnings注解修饰,并且该@SuppressWarning注解包含dagger.android.ScopedInjectorFactory值;

  5. 方法返回类型必须是AndroidInjector.Factory类型;

  6. 如果方法使用了@Binds修饰并且方法参数有且仅有一个,当前方法参数类型必须是AndroidInjector.Factory的子类,这里的T表示@AndroidInjectionKey或@ClassKey注解的方法类型,如下案例:

      @Binds
      @IntoMap
      @ClassKey(GreenActivity.class)
      abstract AndroidInjector.Factory<?> bindBlueActivity(
           BlueActivityComponent.Builder builder);
      }
    

BlueActivityComponent.Builder是AndroidInjector.Factory< GreenActivity>子类

@ContributesAndroidInjector

@ContributesAndroidInjector注解用于修饰方法。

@ContributesAndroidInjector修饰的方法校验规则如下:

  1. 方法必须使用abstract修饰(按理说修饰的是接口方法也ok);

  2. 方法不能有参数;

  3. 方法的父级类必须是@Module修饰的module节点;

  4. 该方法的返回类型不能使用泛型;

  5. @ContributesAndroidInjector#modules里面的节点必须使用@Module注解;

  6. 该方法不能使用@Qualifier修饰的注解修饰;

我们以下面的案例来说下@ContributesAndroidInjector修饰的方法的作用:

@Module
abstract class MainActivityModule {
    @ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
    abstract fun contributeMainActivity(): MainActivity
}

通过Dagger的android模块生成如下代码:

@Module(subcomponents = MainActivityModule_ContributeMainActivity.MainActivitySubcomponent.class)
public abstract class MainActivityModule_ContributeMainActivity {
  private MainActivityModule_ContributeMainActivity() {}

  @Binds
  @IntoMap
  @ActivityKey(MainActivity.class)
  abstract AndroidInjector.Factory<? extends Activity> bindAndroidInjectorFactory(
      MainActivitySubcomponent.Builder builder);

  @Subcomponent(modules = FragmentBuildersModule.class)
  public interface MainActivitySubcomponent extends AndroidInjector<MainActivity> {
    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<MainActivity> {}
  }
}

这里表示的是当前bindAndroidInjectorFactory的返回类型匹配上参数类型。那么bindAndroidInjectorFactory方法在哪里被收集?如下:

@Module
public abstract class AndroidInjectionModule {
  @Multibinds
  abstract Map<Class<? extends Activity>, AndroidInjector.Factory<? extends Activity>>
      activityInjectorFactories();

  ...
}

bindAndroidInjectorFactory方法被AndroidInjectionModule类的activityInjectorFactories方法收集。

@ContributesAndroidInjector修饰的方法生成业务代码规则:

  1. 生成的module类名命名规则:@ContributesAndroidInjector修饰的方法所在module节点(如果module节点是内部类,外部""拼接当前module节点) + "" +当前方法首字母大写后的名称;

  2. 生成module类的内部类规则:@ContributesAndroidInjector修饰的方法的返回类型 + "Subcomponent"生成一个subcomponent接口,;再生成一个Factory抽象类作为subcomponent的内部类;

  3. module类添加@Module(subcomponents=module.subcomponent.class)注解,并且使用public abstract修饰,并且添加一个private无参构造函数;

  4. 添加bindAndroidInjectorFactory方法:

  • (1)方法名:bindAndroidInjectorFactory,abstract修饰;

  • (2)使用@Binds和@IntoMap注解修饰,并且使用@ClassKey(T.class)或@AndroidInjectionKey(T.class)修饰,T表示@ContributesAndroidInjector修饰的方法返回类型;

  • (3)返回类型是AndroidInjector.Factory<? extends T的父级类>;

  • (4)参数名是builder,参数类型是subcomponent.Factory;

  1. 生成的subcomponent接口规则:
  • (1)添加@Subcomponent注解;如果当前@ContributesAndroidInjector注解中包含modules值,那么subcomponent接口添加注解格式如下:@Subcomponent(modules = @ContributesAndroidInjector注解中包含modules值);

  • (2)生成的subcomponent是一个public修饰接口,如果@ContributesAndroidInjector注解的方法中使用了@Scope修饰的注解,那么当前subcomponent接口沿用该@Scope修饰的注解;

  • (3)subcomponent接口继承AndroidInjector< T>,T表示@ContributesAndroidInjector修饰的方法返回类型;

  • (4)subcomponent接口中添加Factory接口(如果是Builder,生成Builder抽象类,那么添加@Subcomponent.Builder注解,继承AndroidInjector.Builder< T>):

  • ① 接口名称是Factory,使用public static修饰,添加@Subcomponent.Factory注解;

  • ②Factory接口继承AndroidInjector.Factory< T>,T表示@ContributesAndroidInjector修饰的方法返回类型。

总结

当前@ContributesAndroidInjector修饰的方法生成的module类和相关方法在component还需要进行二次处理,自行往后看!

可在QQ群:575306647 讨论

源码解析github地址