3.基于Dagger2.38.1版本全面理解注解-inject

前言

当前主要针对@Inject、@AssistedInject、@Assisted、@AssistedFactory注解解说。@AssistedInject、@Assisted和@AssistedFactory三个是Dagger新出现的注解,在一起使用。@Inject主要是用于修饰构造函数、变量和普通方法。

@Inject、@AssistedInject、@Assisted、@AssistedFactory注解

所有使用Dagger注解,建议都不可以使用private修饰,最好使用public修饰,这是铁律。

@Inject和@AssistedInject修饰构造函数

@Inject和@AssistedInject修饰构造函数规则:

  1. 节点的构造函数不允许同时使用Inject注解和AssistedInject注解;

  2. @Inject、@AssistedInject都可以用来修饰构造函数,并且该构造函数不允许使用private修饰,也不能被@Qualifier修饰的注解修饰;

  3. 被Inject或AssistedInject修饰的构造函数不能被@Scope注解修饰的注解修饰;

  4. @Inject或@AssistedInject修饰的构造函数的参数不能是Produced< T>和Producer< T>类型,参数表示依赖,下面有所有依赖来源,以及依赖校验,这里不对赘述;

  5. 被@Inject或@AssistedInject修饰的构造函数如果throws异常,那么异常一定要是RuntimeException或Error或两者子类;

  6. 使用了@Inject或@AssistedInject修饰的构造函数所在父节点不可以被private类使用,该构造函数所在父节点也不能使用abstract修饰,并且如果构造函数所在父节点是一个内部类,那么该内部类必须使用static修饰;

  7. 一个类最多只能有一个构造函数被@Inject或@AssitedInject修饰;

  8. 使用@AssistedInject修饰的构造函数所在的父节点不能被使用@Scope注解修饰的注解修饰;

@Inject修饰变量或普通方法

@Inject修饰变量类型或普通方法的参数类型作为依赖,需要做依赖校验,自行查看下面的依赖校验,我们这里对@Inject修饰变量类型或普通方法进行校验:

  1. @Inject修饰的变量节点不能使用final修饰;也不要使用private和static修饰(可能警告可能报错;

  2. @Inject修饰的普通方法必须是实现类,不能是abstract修饰的抽象类或接口方法;

  3. @Inject修饰的普通方法不要使用private和static修饰(可能报错可能警告);

  4. @Inject修饰的普通方法不能使用泛型类型,并且不能throws异常;

  5. Inject修饰的节点所在父节点最好不要被private修饰(可能警告可能报错);并且Inject修饰的节点所在父节点不能是Kotlin Object或Kotlin Companion Object对象;

@AssistedInject、@Assisted和@AssistedFactory在一起!!!

@AssistedInject仅仅用于修饰构造函数,规则上面已经说了,自行查看。

Assisted修饰的节点规则如下

  1. Assisted只能修饰方法参数,并且仅仅满足以下条件:
  • (1)@Assisted修饰的参数,位于一个被@AssistedInject修饰的构造函数中;

  • (2)@Assisted修饰的参数所在的方法节点是所在父节点中唯一的一个abstract、非static、非private修饰的方法;

  • (3)@Assisted修饰的参数所在的方法 ,如果该方法命名包含"copy" ,那么该方法所在类是一个data类型的kotlin文件;

  1. @Assisted修饰的参数节点不能被Qualifier注解修饰的注解修饰;

  2. @AssistedInject修饰的构造函数或@AssistedFactory修饰的节点中的普通方法都不允许出现重复的@Assisted修饰的参数类型。

AssistedFactory修饰的节点中的方法仅仅针对abstract(接口除外)、非static、非private修饰的方法校验,AssistedFactory注解使用规则如下:

  1. 使用@AssistedFactory修饰的节点仅仅支持抽象类或接口;

  2. 如果@AssistedFactory修饰的节点是内部类,那么必须使用static修饰;

  3. @AssistedFactory修饰的节点必须有且仅有一个abstract、非static、非private的方法节点;

  4. @AssistedFactory修饰的节点中的方法返回类型的构造函数必须使用@AssistedInject修饰;

  5. @AssistedFactory修饰的节点中的方法不允许使用泛型;

  6. @AssistedFactory修饰的节点中的唯一方法传递的参数 和 该方法返回类型中的构造函数使用@Assisted注解修饰的参数 保持一致。

依赖校验

这里面有一个依赖校验的概念,依赖类型有(1)@Inject修饰的变量类型、(2)@Inject修饰的普通方法或构造函数参数类型;(3)@AssistedInject修饰的构造函数排除@Assisted修饰的其他参数类型、(4)component节点中存在的无参方法的返回类型;(5)bindingMethod方法参数类型;

component节点表示使用@Component、@Subcomponent、@ProductionComponent、@ProductionSubcomponent注解的节点;
bindingMethod方法,表示使用@Provides、@Produces和@Binds的方法参数(@BindsOptionalOf和@Multibindings修饰的bindingMethod方法是没有参数的);

校验规则如下:

  1. 依赖节点不能使用通配符;

  2. 依赖节点是MembersInjector< T>(必须存在T)类型,对T表示的类不能使用Qualifier注解修饰的注解修饰;

  • 如果依赖节点是MembersInjector< T>(必须存在T)类型,收集当前T表示的类中使用@Inject修饰的变量或普通方法对其实现实例化。但是!!!个人建议别这么骚操作,最大的不确定性就是实例化过程的参数依赖是否能匹配到;
  1. 还有一些其他细的规则,想了解可以自己去骚操作一番!!!自行看提示!

案例

以一个案例的形式彻底说明以上三个注解,还外送其他注解!!!

1.ComponentProcessor类对XProcessingStep变量实例化:

public class ComponentProcessor {
    @Inject
    XProcessingStep processingStep;
}

2.XProcessingStep作为依赖匹配到ProcessingStepsModule的processingSteps方法:

@Module
interface ProcessingStepsModule {
    @Provides
    static XProcessingStep processingSteps(
            ComponentProcessingStep componentProcessingStep
    ) {
        return componentProcessingStep;
    }

	//processingSteps或者这么写
	@Binds
	 XProcessingStep processingSteps(ComponentProcessingStep componentProcessingStep);
}
  1. ComponentProcessingStep作为依赖匹配到ComponentProcessingStep类使用@Inject修饰的构造函数;

    final class ComponentProcessingStep extends XProcessingStep {
    @Inject
    ComponentProcessingStep(
    ComponentRequestRepresentations componentRequestRepresentations) {
    this.componentRequestRepresentations = componentRequestRepresentations;
    }
    }

  2. ComponentProcessingStep类使用@Inject修饰的构造函数的参数作为依赖匹配到ComponentRequestRepresentations使用Inject修饰的构造函数:

    public final class ComponentRequestRepresentations {
    @Inject
    ComponentRequestRepresentations(
    LegacyBindingRepresentation.Factory legacyBindingRepresentationFactory) {

         this.legacyBindingRepresentationFactory = legacyBindingRepresentationFactory;
        LegacyBindingRepresentation legacyBindingRepresentation = legacyBindingRepresentationFactory.create(true,new Binding(),new SwitchingProviders());
     }
    

    }

  3. LegacyBindingRepresentation.Factory匹配到LegacyBindingRepresentation类中@AssistedFactory修饰的Factory接口,并且该接口的create方法的返回类型匹配到@AssistedInject修饰的LegacyBindingRepresentation构造函数,创建LegacyBindingRepresentation对象是@Assisted修饰的参数通过Factory接口create方法传递进入;

     final class LegacyBindingRepresentation{
     @AssistedInject
         LegacyBindingRepresentation(
                 @Assisted boolean isFastInit,
                 @Assisted Binding binding,
                 @Assisted SwitchingProviders switchingProviders,
                 ...) {
         }
     
     	@AssistedFactory
         static interface Factory {
             LegacyBindingRepresentation create(
                     boolean isFastInit,
                     Binding binding,
                     SwitchingProviders switchingProviders
             );
         }
     }
    
  4. 必须有一个承载ComponentProcessor类中@Inject修饰变量实例化的容器,并且ComponentProcessor类中@Inject修饰变量实例化的匹配(1)要么是@Inject修饰的构造函数;(2)要么必须是容器关联到的绑定,e.g.ProcessingStepsModuleprocessingSteps方法

     @Component(
         modules = {
                 ProcessingStepsModule.class//关联
         }
     )
     interface ProcessorComponent {
     	//表示当前容器注入ComponentProcessor中使用@Inject修饰的变量实例对象
         void inject(ComponentProcessor processor);
    
         static Factory factory() {
             return DaggerComponentProcessor_ProcessorComponent.factory();
         }
    
         @Component.Factory
         interface Factory {
             @CheckReturnValue
             ProcessorComponent create();
         }
     }
    

总结

以上说的我感觉挺爽的,也感觉抓到了重点。如果有不完善或者不足之处欢迎指正!!!

可在QQ群:575306647 讨论

源码解析github地址

你可能感兴趣的:(源码实际应用,android)