本文是狂技能系列关于剑柄的第四篇文章!在这篇文章中,我们将探讨如何编写一个自定义的刀柄扩展。如果需要了解本系列的前三篇文章,请参考:
希尔特介绍了希尔特测试的最佳实践。如果你更喜欢通过视频了解这些内容,可以在这里查看3360。
视频加载.
剑柄延伸——MAD技能
案例: WorkManager扩展Hilt extension是一个用于生成代码的库,通常由注释处理器实现。生成的代码作为刀柄依赖注入图的模块或入口点。
Jetpack中的WorkManager集成库就是一个扩展的例子。Work extension有助于我们减少向工作人员提供依赖关系时所需的模板代码和配置。该库由两部分组成,即androidx.hilt:hilt-work和androidx。hilt3360hilt编译器。第一部分包含HiltWorker注释和一些运行时辅助类。第二部分是注释处理器,它根据第一部分中的注释提供的信息生成模块。
的扩展使用起来非常简单,只需在你的Worker上添加@HiltWorker annotation 3360即可。
@ hiltworkerpublic类示例worker扩展worker {//.}扩展编译器将生成一个带有@Module注释的类3360。
@ Generated(‘ androidx . hilt . androidxhiltprocessor ‘)@ Module @ install in(singleton component . class)@ originating element(toplevel class=example worker . class)公共接口example worker _ hilt Module { @ Binds @ into map @ string key(‘ my . app . exmaple worker ‘)workers istedfactory扩展ListenableWorker绑定(example worker _ assisted factory factory工厂);}此模块为可以访问HiltWorkerFactory的worker定义一个绑定。然后,WorkerManager被配置为使用工厂,这样worker的依赖注入就可用了。
Hilt聚合支持扩展的一个关键机制是,Hilt可以从类路径中发现模块和入口点。这称为聚合,因为模块和入口点通过注释@HiltAndroidApp聚合到应用程序中。
由于Hilt的聚合能力,任何通过添加@InstallIn注释生成@Module和@EntryPoint的工具都可以被Hilt发现,并在编译时成为Hilt DI图的一部分。这使得扩展可以很容易地作为插件集成到Hilt中,而不需要开发者做任何额外的工作。
注释处理器生成代码的通常方式是使用注释处理器。在源文件被转换成类文件之前,注释处理器将在编译器中运行。当资源有处理器声明的支持的注释时,处理器将处理它。处理器可以生成需要处理的进一步的方法,所以编译器将循环注释处理器,直到没有新的内容生成。一旦所有的链接都完成了,编译器就会把源文件转换成类文件。
标注处理图
由于这种循环机制,处理器可以相互交互。这非常重要,因为它允许Hilt的注释处理器处理其他处理器生成的@Module或@EntryPoint类。这也意味着你的扩展也可以建立在别人写的扩展之上!
管理器扩展处理器根据带有@HiltWorker注释的类生成代码,验证注释的用法,并使用JavaPoet之类的库生成代码。
在Hilt API中有两个重要的注释: @GeneratesRootInput和@OriginatingElement。扩展应该使用这些注释来正确地与Hilt集成。
扩展应该使用@GeneratesRootInput来启用代码生成的注释。这让Hilt注释处理器知道它应该在生成组件之前完成扩展注释处理器的工作。例如,@HiltWorker批注本身就是由@ generatesrootput批注修饰的:
@ target(element type . type)@ retention(retention policy . class)@ generatesrootinputpublic @ interfacehiltworker { }用@Module生成,用@EntryPoint和@InstallIn批注的类需要添加@OriginatingElement批注,该批注的输入参数是触发模块或入口点生成的顶级类。这是Hilt判断生成的模块和入口点是否进行本地测试的依据。比如在hilt test中定义了一个带有@ Hiltworker注释的内部类,模块的初始元素是测试值。
测试用例如下:3360
@ hiltandroidtestclasssampletest { @ hilt worker classtestworker extensions worker {//…} }生成的模块包含@OriginatingElement批注:
@ module @ install in(singleton component . class)@ originating element(top level class=sample test . class)公共接口sample test _ test worker _ _ hilt module {/…}体验一下,hilt扩展支持多种可能。下面是一些创建扩展的经验:3360
项目中的常见模式
如果在你的项目中有一个创建模块或入口点的通用模式,那么很有可能通过使用Hilt扩展来实现自动化。例如,如果每个实现特定接口的类都必须创建一个具有多个绑定的模块,那么可以创建一个扩展,只需向实现类添加注释,就可以生成多个绑定模块。
支持非标准成员注入
对于那些框架中已经支持的具有实例化能力的成员注入类型,我们需要创建一个@EntryPoint。如果有多个类型需要由成员注入,那么自动创建入口点的扩展将会很有用。例如,需要通过ServiceLoader发现服务实现的库负责实例化发现的服务。为了将依赖项注入到服务实现中,您必须创建一个@EntryPoint。使用Hilt扩展,可以通过在实现类上添加注释来完成入口点的自动生成。扩展可以进一步生成代码来使用入口点,比如服务实现的基类。这类似于@ AndroidEntryPoint为Activity创建@EntryPoint,并创建一个基类,该基类使用生成的入口点在Activity中执行成员注入。
镜像绑定
有时,您需要使用不同的限定符来镜像或重新声明绑定。当有自定义组件时,这可能更常见。为了避免丢失重新声明的绑定,您可以创建一个句柄扩展来自动生成带有其他镜像绑定的模块。例如,考虑具有不同依赖实现的应用程序中的“付费”和“免费”订阅。然后,每一层都有两个不同的定制组件,这样您就可以确定依赖关系的范围。当添加没有范围的通用绑定时,定义绑定的模块可以在其@InstallIn中包含两个组件,或者可以在父组件(通常是单例组件)中加载。但是当绑定被限定范围时,模块必须被复制,因为需要不同的限定符。通过实现一个扩展,可以生成两个模块,这可以避免样板代码,并确保不会遗漏任何通用绑定。
总结一下Hilt的扩展,可以进一步增强代码库中的依赖注入能力,因为它们可以和其他Hilt还不支持的库集成。总结一下,一个扩展通常由两部分组成,包括扩展注释的运行时部分和生成@Module或@EntryPoint的代码生成器(通常是注释处理器)。扩展的运行时部分可能有额外的辅助类,它们使用声明绑定在生成的模块或入口点中。代码生成器还可以生成与扩展相关的附加代码,这些代码不需要专门生成模块和入口点。
该扩展必须使用两个注释来正确地与柄3360交互
@GeneratesRootInput被添加到扩展注释中。@OriginatingElement通过扩展添加到生成的模块或入口点。最后,您可以检查一下hilt-install-binding项目,这是一个简单扩展的例子,展示了本文中提到的概念。
疯狂技能系列里关于剑柄的都是这些。如果你想看完整的视频,请移至剑柄狂技能播放列表。感谢阅读这篇文章!
欢迎您点击这里向我们提交您的反馈,或者分享您喜欢的内容和发现的问题。您的反馈对我们非常重要,谢谢您的支持!
暂无讨论,说说你的看法吧