如何使用Dagger Hilt向Kotlin扩展函数注入参数?
问题描述
我有一个将Int格式化为货币字符串的Kotlin扩展函数:
fun Int.asCurrency(formatter: NumberFormat): String { formatter.maximumFractionDigits = 0 return formatter.format(this) }
因为在RecyclerView中调用时不想每次创建新的NumberFormat实例,我会传入已有的实例,也试过用单例类复用:
object Formatter { val currencyFormatter: NumberFormat = NumberFormat.getCurrencyInstance(Locale.getDefault()) } fun Int.asCurrency(): String { Formatter.currencyFormatter.maximumFractionDigits = 0 return Formatter.currencyFormatter.format(this) }
现在我在学习依赖注入,想用Dagger Hilt给这个函数注入NumberFormat实例,尝试了以下实现:
@Module @InstallIn(SingletonComponent::class) object FormatterModule { @Singleton @Provides fun provideCurrencyFormatter(): NumberFormat { return NumberFormat.getCurrencyInstance(Locale.getDefault()) } } @Inject fun Int.asCurrency(formatter: NumberFormat): String { formatter.maximumFractionDigits = 0 return formatter.format(this) }
但这个方案没用,调用函数时还是得传参数。后来试了字段注入:
@Inject fun Int.asCurrency(): String { lateinit var formatter: NumberFormat formatter.maximumFractionDigits = 0 return formatter.format(this) }
结果编译报错:error: Dagger does not support injection into static methods。
想问:如何向Kotlin扩展函数注入参数?或者至少怎么给普通Kotlin函数注入参数?
解决方案
1. 封装工具类间接实现注入
Kotlin扩展函数本质是静态方法,Dagger Hilt无法直接给静态方法注入依赖。最稳妥的方式是把格式化逻辑封装成一个支持依赖注入的工具类,再让扩展函数调用这个工具类:
class CurrencyFormatter @Inject constructor( private val numberFormat: NumberFormat ) { init { // 初始化配置,避免每次调用重复设置 numberFormat.maximumFractionDigits = 0 } fun formatInt(value: Int): String { return numberFormat.format(value) } } // 扩展函数调用工具类 fun Int.asCurrency(formatter: CurrencyFormatter): String { return formatter.formatInt(this) }
在需要调用的地方(比如RecyclerView的Adapter),先通过Hilt注入CurrencyFormatter实例,再调用扩展函数时传入该实例即可。
2. 通过Hilt入口点获取依赖(适配特殊场景)
如果某些场景下无法直接注入工具类(比如纯顶层函数场景),可以用Hilt的@EntryPoint获取依赖实例:
// 定义入口点接口 @EntryPoint @InstallIn(SingletonComponent::class) interface FormatterEntryPoint { fun getCurrencyFormatter(): NumberFormat } // 扩展函数中通过入口点获取实例 fun Int.asCurrency(context: Context): String { val entryPoint = EntryPointAccessors.fromApplication( context.applicationContext, FormatterEntryPoint::class.java ) val formatter = entryPoint.getCurrencyFormatter() formatter.maximumFractionDigits = 0 return formatter.format(this) }
调用时传入上下文即可,但这种方式会增加代码与Hilt的耦合度,建议仅在必要时使用。
3. 普通函数的注入方式
普通函数如果是类的成员函数,可以直接通过构造注入或字段注入依赖:
class NumberService @Inject constructor( private val formatter: NumberFormat ) { fun formatCurrency(value: Int): String { formatter.maximumFractionDigits = 0 return formatter.format(value) } }
如果是顶层函数,同样无法直接注入,建议要么封装到类中,要么通过上述入口点方式获取依赖。
内容的提问来源于stack exchange,提问作者Alraj
相关产品推荐
相关产品推荐

