5.基于Dagger2.38.1的hilt源码-AggregatedDepsProcessor

249 阅读5分钟

前言

本篇主要是处理@InstallIn和@TestInstallIn、@Module、@EntryPoint和@EarlyEntryPoint和@GeneratedEntryPoint和@ComponentEntryPoint注解。这些注解只能用于修饰类或接口。

校验并且生成PkgPrivateMetadata对象

校验规则

  1. @InstallIn和@TestInstallIn:当前节点只允许使用其中的一个注解,只允许使用一次;

  2. @EntryPoint、@EarlyEntryPoint、@GeneratedEntryPoint和@ComponentEntryPoint:当前节点只允许使用其中的一个注解,只允许使用一次;

  • (1)@EntryPoint和@GeneratedEntryPoint的区别在于(当然并不是强制的要求),@EntryPoint是用户使用的注解,@GeneratedEntryPoint是通过代码生成的类使用的注解;e.g.例如ViewComponentManager.ViewWithFragmentComponentBuilderEntryPoint和Application_GeneratedInjector可自行去查看;

  • (2)@GeneratedEntryPoint使用了@GeneratesRootInput修饰,会在dagger.hilt.processor.internal.generatesrootinput.codegen包下生成dagger_hilt_internal_ComponentEntryPoint类;

  • (3)@EarlyEntryPoint注解修饰的earlyEntryPoint节点生成的类在dagger.hilt.android.internal.earlyentrypoint.codegen包下,并且当前节点使用@AggregatedEarlyEntryPoint(earlyEntryPoint = earlyEntryPoint节点名)修饰,@EarlyEntryPoint修饰的节点应用于测试;

  • (4)@ComponentEntryPoint修饰的节点会放在生成的类的注解@AggregatedDeps#componentEntryPoints中;

  1. @Module:当前节点只允许使用一次Module注解;

  2. @InstallIn或@TestInstallIn注解修饰的节点。该节点要么使用@Module修饰,要么使用@EntryPoint或@EarlyEntryPoint或@GeneratedEntryPoint或@ComponentEntryPoint修饰;

  3. @Module修饰的节点不允许同时使用@EntryPoint或@EarlyEntryPoint或@GeneratedEntryPoint或@ComponentEntryPoint修饰;

  4. @InstallIn或@TestInstallIn注解修饰的节点同时使用@Module修饰,我们称之为module节点:

  • (1)module节点必须是类或接口;

  • (2)module节点是顶级类(再上一级就是包) || module节点使用static修饰 || module节点使用abstract修饰 || module节点的父节点使用@HiltAndroidTest修饰;

  • (3)module节点是ApplicationContextModule类 || module节点不需要实例化(module节点何时需要实例化:module节点中的所有bindingMethod方法既不是static就是也不是abstract修饰,并且module不是 Kotlin compainionObject类型) || module不存在构造函数,或者构造函数无参并且没有使用private修饰;

  • (4) module节点中abstract修饰的bindingMethod方法必须使用@Binds或@Multibinds或@Provides或@BindsOptionalOf修饰;

  • (5)@TestInstallIn修饰的module节点不能嵌套在(或源自)@HiltAndroidTest 注释的类中;

  • (6)@TestInstallIn注解的replaces方法必须存在至少一个值;

  • (7) @TestInstallIn注解的replaces方法中的值类型必须使用@InstallIn修饰;

  • (8)@TestInstallIn#replaces()中的值类名称不允许使用"HiltWrapper_"作为开头;

  • (9) 如果当前module节点所在的包路径不是dagger.hilt开头,那么@TestInstallIn#replaces()的值类也不能在dagger.hilt开头开头的包下;

  • (10)@TestInstallIn#replaces()的值类型不能嵌套在(或源自)@HiltAndroidTest 注释的类中;

  1. @InstallIn注解修饰的节点同时使用@EntryPoint或@EarlyEntryPoint或@GeneratedEntryPoint或@ComponentEntryPoint修饰,当前节点称之为entryPoint节点:
  • (1)@TestInstallIn注解只能和@Module一起使用,不能和@EntryPoint或@EarlyEntryPoint或@GeneratedEntryPoint或@ComponentEntryPoint一起使用;

  • (2)entryPoint节点只能是接口;

  • (3)@EarlyEntryPoint修饰的节点使用的注解@InstallIn的value值类型只能是SingletonComponent接口;

  • (4)@EarlyEntryPoint 修饰的节点 不能嵌套在(或源自)@HiltAndroidTest 修饰的类 中。 此要求是为了避免与其他特定于测试的入口点混淆。

  1. @InstallIn的value值或者@TestInstallIn的components值类型 - 必须使用@DefineComponent修饰;

生成PkgPrivateMetadata对象属性

使用@InstallIn或@TestInstallIn修饰的节点(该节点同时使用@Module修饰 或@EntryPoint、@EarlyEntryPoint、@GeneratedEntryPoint和@ComponentEntryPoint修饰),该节点存在不会生成当前PkgPrivateMetadata对象的情况:

  1. 如果该节点是public修饰类或接口(存在父级节点也是public修饰的类或接口),非kotlin文件,那么不需要生成当前PkgPrivateMetadata对象;

  2. 条件1不满足的情况下,在判断当前节点是使用@Module修饰的module节点,并且该module节点需要被实例化(module节点中的bindingMethod方法既不是static就是也不是abstract修饰,并且module不是 Kotlin compainionObject类型),那么不需要生成当前PkgPrivateMetadata对象。

PkgPrivateMetadata对象属性如下:

  1. TypeElement typeElement:使用@InstallIn或@TestInstallIn修饰的节点类型(该节点同时使用@Module修饰 或@EntryPoint、@EarlyEntryPoint、@GeneratedEntryPoint和@ComponentEntryPoint修饰;

  2. Optional optionalInstallInAnnotationMirror:当前节点使用的@InstallIn或@TestInstallIn注解;

  3. ClassName annotation:当前节点使用的@Module 或 @EntryPoint、@EarlyEntryPoint、@GeneratedEntryPoint和@ComponentEntryPoint注解的ClassName类型;

PkgPrivateModuleGenerator生成类

当前节点使用@InstallIn或@TestInstallIn修饰 并且使用 @Module修饰,并且该module节点非public修饰 ,并且当前module节点不需要实例化(实例化条件:module节点中的bindingMethod方法既不是static就是也不是abstract修饰,并且module不是 Kotlin compainionObject类型)。

当前hilt源码中有几个类需要通过当前类生成新类:

  1. DefaultViewModelFactories.ActivityModule 生成HiltWrapper_HiltViewModelFactory_ViewModelModule 类:

     package dagger.hilt.android.internal.lifecycle;
    
     import dagger.Module;
     import dagger.hilt.InstallIn;
     import dagger.hilt.android.components.ViewModelComponent;
     import dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.ViewModelModule;
     import dagger.hilt.codegen.OriginatingElement;
     
     @Module(
         includes = {ViewModelModule.class}
     )
     @OriginatingElement(
         topLevelClass = HiltViewModelFactory.class
     )
     @InstallIn({ViewModelComponent.class})
     public final class HiltWrapper_HiltViewModelFactory_ViewModelModule {
         public HiltWrapper_HiltViewModelFactory_ViewModelModule() {
         }
     }
    
  2. ActivityRetainedComponentManager.LifecycleModule 生成HiltWrapper_ActivityRetainedComponentManager_LifecycleModule类:

     package dagger.hilt.android.internal.managers;
     
     import dagger.Module;
     import dagger.hilt.InstallIn;
     import dagger.hilt.android.components.ActivityRetainedComponent;
     import dagger.hilt.android.internal.managers.ActivityRetainedComponentManager.LifecycleModule;
     import dagger.hilt.codegen.OriginatingElement;
     
     @Module(
         includes = {LifecycleModule.class}
     )
     @OriginatingElement(
         topLevelClass = ActivityRetainedComponentManager.class
     )
     @InstallIn({ActivityRetainedComponent.class})
     public final class HiltWrapper_ActivityRetainedComponentManager_LifecycleModule {
         public HiltWrapper_ActivityRetainedComponentManager_LifecycleModule() {
         }
     }
    
  3. ActivityModule生成HiltWrapper_ActivityModule 类

     package dagger.hilt.android.internal.modules;
     
     import dagger.Module;
     import dagger.hilt.InstallIn;
     import dagger.hilt.android.components.ActivityComponent;
     import dagger.hilt.codegen.OriginatingElement;
     
     @OriginatingElement(
         topLevelClass = ActivityModule.class
     )
     @InstallIn(ActivityComponent.class)
     @Module(
         includes = ActivityModule.class
     )
     public final class HiltWrapper_ActivityModule {
     }
    

PkgPrivateEntryPointGenerator生成类

当前节点使用@InstallIn或@TestInstallIn修饰 并且使用 @EntryPoint、@EarlyEntryPoint、@GeneratedEntryPoint和@ComponentEntryPoint修饰,并且该emtryPoint节点非public修饰。

demo和hilt源码中都有符合条件的类:

  1. HiltViewModelFactory.ActivityCreatorEntryPoint生成HiltWrapper_HiltViewModelFactory_ActivityCreatorEntryPoint类:

     @OriginatingElement(
         topLevelClass = HiltViewModelFactory.class
     )
     @EntryPoint
     @InstallIn(ActivityComponent.class)
     public interface HiltWrapper_HiltViewModelFactory_ActivityCreatorEntryPoint extends HiltViewModelFactory.ActivityCreatorEntryPoint {
     }
    
  2. ActivityRetainedComponentManager.ActivityRetainedComponentBuilderEntryPoint生成HiltWrapper_ActivityRetainedComponentManager_ActivityRetainedComponentBuilderEntryPoint类:

    @OriginatingElement( topLevelClass = ActivityRetainedComponentManager.class ) @EntryPoint @InstallIn(SingletonComponent.class) public interface HiltWrapper_ActivityRetainedComponentManager_ActivityRetainedComponentBuilderEntryPoint extends ActivityRetainedComponentManager.ActivityRetainedComponentBuilderEntryPoint { }

  3. ActivityRetainedComponentManager.ActivityRetainedLifecycleEntryPoint生成HiltWrapper_ActivityRetainedComponentManager_ActivityRetainedLifecycleEntryPoint类:

     @OriginatingElement(
         topLevelClass = ActivityRetainedComponentManager.class
     )
     @EntryPoint
     @InstallIn(ActivityRetainedComponent.class)
     public interface HiltWrapper_ActivityRetainedComponentManager_ActivityRetainedLifecycleEntryPoint extends ActivityRetainedComponentManager.ActivityRetainedLifecycleEntryPoint {
     }
    

AggregatedDepsGenerator生成类

当前节点使用@InstallIn或@TestInstallIn修饰,并且使用@Module修饰的节点 或使用@EntryPoint、@EarlyEntryPoint、@GeneratedEntryPoint和@ComponentEntryPoint修饰,该节点使用public修饰,或者如果是module节点需要被实例化的情况下,使用当前对象生成相关类。

demo + hilt源码中处理这部分的类非常多。我们截图查看:

1.demo中的案例:

(1)这个是demo直接生成的:

在这里插入图片描述

(2)这个是二次生成的:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.hilt源码中的案例:

一定要看,最少要过一遍。

在这里插入图片描述

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

总结

以上代码可以看出,是对@InstallIn注解的处理,有一部分是对二次生成的类进行再次代码生成,如UserDetailsFragment_GeneratedInjector

对照hilt生成代码关系图好好理解一下,里面的内容非常多。