Hilt原理分析三(xxx_Factory的作用)

简介: xxx_Factory的作用

系列文章

上一篇文章的末尾,提到了ApplicationModel_Factory这个类,当时在Application实现依赖注入的时候并没有用到生成的这个类,就没有继续介绍了,这篇我们就来了解下。

在Activity中实现依赖注入

因为在Application中依赖注入不会用到这个ApplicationModel_Factory,所以看下在Activity中实现依赖注入会不会用到ApplicationModel_Factory,为了更贴近语义,将ApplicationModel修改为ActivityModel,然后注入到Activity中,代码如下

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    @Inject
    lateinit var model: ActivityModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        model.doSomething()
    }
}

编译运行下,打印的日志如下

290215b130ed3bfaecfde6de1cba4da.png

再看下编译后生成的文件,如下

6ec0240dc5ea77f0a5d77dff02c162a.png

可以看到这里新生成了两个文件,Hilt也是通过这两个文件实现Activity中的依赖注入的,下面通过这两个文件来了解下Hilt在Activity实现依赖注入的原理。

Hilt_MainActivity分析

通过前面两篇的内容可以知道,MainActivity编译后会继承至Hilt_MainActivity,看下Hilt_MainActivity代码

9ca6990bf8412340a7e8c696bd3179a.png

从上面的截图中可以看到,通过Hilt_MainActivity的构造方法会注册一个监听,当这个类与Context关联时会收到回调,然后继续调用inject方法,inject方法的代码如下

e9f2246c4a38f3aa6437356d8ebff4c.png

因为inject方法调用的方法会较多,这里就画出调用的时序图,重要的地方再讲下代码,部分时序图如下

b09486d4c0bbf2c7192302298879e82.png

这里看下时序图上的getViewModelProvider方法的代码,如下

private ViewModelProvider getViewModelProvider(
      ViewModelStoreOwner owner, Context context) {
    return new ViewModelProvider(
        owner,
        new ViewModelProvider.Factory() {
          @NonNull
          @Override
          @SuppressWarnings("unchecked")
          public <T extends ViewModel> T create(@NonNull Class<T> aClass) {
            ActivityRetainedComponent component =
                EntryPointAccessors.fromApplication(
                    context, ActivityRetainedComponentBuilderEntryPoint.class)
                    .retainedComponentBuilder()
                    .build();
            return (T) new ActivityRetainedComponentViewModel(component);
          }
        });
  }

可以看到这个方法创建了ViewModelProvider类,想必看到这里会意识到这个类与ViewModel有关,好了,先跟到这里。

再回到上面时序图上generatedComponent方法

023cfec1255b895b95b1be36b255838.png

这个方法的代码如下

9a4cea93106be130426dc711ae14910.png

上面的时序图是顺着componentManager方法跟下去的画的,这次来跟下generatedComponent方法,时序图如下

361b42217a66f95f3d789b19ce65f0b.png

这个时序图有两个地方需要注意下,如下图

0951440fd374d57d57276476e3da7c6.png

第一处方法的代码如下

54285a0998aca4bca478776f5f7af3c.png

重点是红框内的内容,先看下

EntryPoints.get(         activityRetainedComponentManager, ActivityComponentBuilderEntryPoint.class)

这段代码,get方法的内容如下

3bbb3cb4161b68747d3a792a08f7a9e.png

这段代码要留意一下,在后面代码执行的时候还会调用到这里,只是参数component不同,这里就不具体的分析了,继续看从这里跟下去的时序图,如下

7669d69acafecc62f5c0e43e76b567a.png

这里需要说明一下,时序图上面的ARComponentManager是ActivityRetainedComponentManager,为了方便画时序图就缩写了一下。

继续看下2处的代码,如下

7c8ab22da13092c16e8fe1d7fec5b1c.png

这里的viewModelProviderget方法,最终会调用到下面的方法

8750daae529c7a349bfc18beb53566b.png

最后调用到红框标记的地方,看到这里有没有感觉mFactory.create方法似曾相识,如果忘记的话,这里我再贴一下代码,帮助回忆下前面内容

7f321ad0966ea627bb47c11a22e8ee8.png

没错,这里就调用了文章前面跟到crate方法,好了,这里就可以继续往下看create方法的代码了,先看下

EntryPointAccessors.fromApplication(
                    context, ActivityRetainedComponentBuilderEntryPoint.class)

这段代码做了什么,fromApplication方法代码如下

0286607a7839ea88b74378322ac89ff.png

这里又调用了EntryPointsget方法,前面已经贴过代码了,这里就不看里面的代码了。这段代码调用后返回的对象是DaggerMyApplication_HiltComponents_SingletonC实例,后面分析就简单了,大家自己跟下就行,最终create方法执行完,返回的是ActivityRetainedCImpl对象。

好了,还记得我们现在是从哪里跟下来的吗?是从下面的方法,红框内的代码得到的ActivityRetainedCImpl对象,

94b641f44e88661887efec936862099.png

然后这个方法调用完,返回的是ActivityCImpl对象。好了,到这里终于快结束了,到这里我们只分析完了Hilt_MainActivity类的inject方法的前半部分

25fbe07ba028e8b97ae613722c83813.png

接着就是调用了ActivityRetainedCImplinjectMianActivity方法,代码如下

20ef4899c3573426e2daeb5b206c85f.png

最后调用到

MainActivity_MembersInjector.injectModel(instance, new ActivityModel());

这句代码。injectModel的代码如下

cf2d63f9e3ee7a47b68f7abf28e29ac.png

好了,这里就把ActivityModel注入到了MainActivity中。

纳尼,好像不对,这里还是没有解释生成的ActivityModel_Factory类的作用呀!是呀,还是没有发现ActivityModel_Factory类的作用呀,想要发现ActivityModel_Factory类的作用,还需要稍微修改下代码,新建Activity2Model

4cc251ee6ec0f152ae0d9bca07a887d.png

里面的代码如下

8d42f46ae665c2bd447b13ba07930a8.png

在修改ActivityModel类中的代码如下

3707615ae5fccbf9f069c31c2082a90.png

好了,现在再来看ActivityRetainedCImplinjectMianActivity方法的代码

1de8df6cc0d7b821282dfd5c54683d7.png

可以发现injectMainActivity2中的代码和前面的已经不一样了,好,继续往下跟,看下和以前不一样的地方,就是

activityModel的代码

0710bccd18f262b227573a7509d93b6.png

好了,总算找到了ActivityModel_Factory了,到这里也就知道为什么Hilt会为我们生成xxx_Factory类了。

总结

文章首先是分析了Hilt_MainActivity,发现最后和Hilt_MyApplication一样会走到DaggerMyApplication_HiltComponents_SingletonC类中,最后调用到ActivityCImpl类中的injectMainActivity方法实现依赖注入,然后由分析了一下为什么Hilt会生成xxx_Factory类,以及它的作用。文章只讲解了重要的代码,如果有不理解的地方可以跟着文章中的时序图自己分析下,多分析分析,就会理解了。


相关文章
|
6月前
|
Java 数据库连接 API
SpringBoot【问题 01】借助@PostConstruct解决使用@Component注解的类用@Resource注入Mapper接口为null的问题(原因解析+解决方法)
SpringBoot【问题 01】借助@PostConstruct解决使用@Component注解的类用@Resource注入Mapper接口为null的问题(原因解析+解决方法)
733 0
|
XML Java 数据格式
面试题@Component和@Bean的区别
面试题@Component和@Bean的区别
258 0
|
XML SpringCloudAlibaba Java
Spring注解配置:@Configuration 和 @Component 区别及原理详解
随着`Spring Boot`的盛行,注解配置式开发受到了大家的青睐,从此告别了基于`Spring`开发的繁琐`XML`配置。这里先来提纲挈领的了解一下`Spring`内部对于配置注解的定义,如`@Component、@Configuration、@Bean、@Import`等注解,从功能上来讲,这些注解所负责的功能的确不相同,但是
342 1
|
Java 索引 Spring
【Spring注解必知必会】深度解析@Component注解实现原理
【Spring注解必知必会】深度解析@Component注解实现原理
428 0
【Spring注解必知必会】深度解析@Component注解实现原理
|
XML 缓存 Java
Spring IoC源码学习:context:component-scan 节点详解
在 Spring IoC:parseCustomElement详解 中,我们介绍了自定义命名空间节点解析的大部分内容,但是还剩下节点解析的具体过程。本文将以<context:component-scan /> 节点为例子,介绍自定义命名空间 context 的 component-scan 节点的解析过程。
231 0
Spring IoC源码学习:context:component-scan 节点详解
|
XML Java 数据格式
《SpringBoot系列八》:Spring注解别名@AliasFor和覆盖(含原理)
《SpringBoot系列八》:Spring注解别名@AliasFor和覆盖(含原理)
615 0
|
消息中间件 XML 运维
Spring源码分析(九)lazy-init 在Spring中是怎么控制加载的
ApplicationContext实现的默认行为就是在启动时将所有singleton bean提前进行实例化(也就是依赖注入)。提前实例化意味着作为初始化过程的一部分,ApplicationContext实例会创建并配置所有的singleton bean。通常情况下这是件好事,因为这样在配置中的任何错误就会即刻被发现(否则的话可能要花几个小时甚至几天)。