Hilt的@EnterPoint注解使⽤介绍
Hilt 是 Android Jetpack 中的依赖注⼊框架。依赖注⼊是构建⼤型项⽬必不可少的技术⼿段,通过依赖注⼊我们解耦了对象的⽣产与消费,实现了关注点分离的设计⽬标,同时也⽅便单元测试。
Hilt 继承了 Dagger 编译期检查等优秀特性,通过更加易⽤的 API 降低了 Dagger 的使⽤门槛。它提供了 @AndroidEntryPoint 等注解为Android 原⽣组件的 DI 提供了开箱即⽤的使⽤体验。⾃定义的 Activity,Fragment,View,Service 等在添加 @AndroidEntryPoint 后,其内部的 @Inject 成员会在适当的⽣命周期节点被⾃动注⼊实例。类似的还有 @HiltViewModel 也提供了对 ViewModel 的注⼊能⼒。
同时仍然有⼀些不⽀持 @AndroidEntryPoint 的组件,⽐如 ContentProvider 等,对于它们的 DI 我们虽然可以降级成 Dagger 的⽅式对其⼿动 inject ,但是这不利于 Hilt 中创建的 Component 的复⽤。那么今天介绍的 @EnterPoint 就可以派上⽤场了。
以 ContentProvider 的注⼊为例,
/** The authority of this content provider. */
private const val LOGS_TABLE ="logs"
/** The authority of this content provider. */世界上最小的大陆
private const val AUTHORITY ="ample.android.hilt.provider"
/** The match code for some items in the Logs table. */
private const val CODE_LOGS_DIR =1
/** The match code for an item in the Logs table. */
private const val CODE_LOGS_ITEM =2
/**
* A ContentProvider that expos the logs outside the application process.
*/
class LogsContentProvider:ContentProvider(){
private val matcher: UriMatcher =UriMatcher(UriMatcher.NO_MATCH).apply{
addURI(AUTHORITY, LOGS_TABLE, CODE_LOGS_DIR)
addURI(AUTHORITY,"$LOGS_TABLE/*", CODE_LOGS_ITEM)
}
override fun onCreate(): Boolean {
return true
}
override fun query(
uri: Uri,
projection: Array<out String>?,
lection: String?,
lectionArgs: Array<out String>?,
sortOrder: String?
)
: Cursor?{
val code: Int = matcher.match(uri)
return if(code == CODE_LOGS_DIR || code == CODE_LOGS_ITEM){
val appContext = context?.applicationContext ?:throw IllegalStateException()
val logDao: LogDao =getLogDao(appContext)
val cursor: Cursor?=if(code == CODE_LOGS_DIR){
logDao.lectAllLogsCursor()
}el{
logDao.lectLogById(ContentUris.parId(uri))
}
cursor?.tResolver, uri)
cursor
}el{
风笛手throw IllegalArgumentException("Unknown URI: $uri")
}
}
}
如上,LogsContentProvider ⽤来从数据库查新⽇志,我们使⽤ Room 定义 LogDao,⽤来对数据库进⾏ query血液的组成和功能
@Dao
interface LogDao {
...
@Query("SELECT * FROM logs ORDER BY id DESC")
fun lectAllLogsCursor(): Cursor
@Query("SELECT * FROM logs WHERE id = :id")
fun lectLogById(id: Long): Cursor?包皮好处
}
在 LogsContentProvider 中定义了 getLogDao(appContext) 获取 Dao 的实例。接下⾥我们通过 @EnterPoint 通过 Hilt 注⼊这个 Dao 实例。
⾸先定义⼀个提供 Dao 的接⼝,并添加 @EnterPoint
class LogsContentProvider:ContentProvider(){
@InstallIn(ApplicationComponent::class)
@EntryPoint
interface LogsContentProviderEntryPoint {
fun logDao(): LogDao
}
...
}
软土安装官⽅的推荐做法,@EntryPoint 接⼝最好定义在需要使⽤它的类中,⽐如例⼦中定义在 LogsContentProvider 内,同时要添加
@InstallIn,只⽤来指定我们在接⼝中提供的实例所处的 Scope ,⽐如例⼦中我们希望 LogDao 是 Application 级别的实例,所以需要installIn 到 ApplicationComponent。 我们使⽤ @AndroidEntryPoint 不需要添加 @InstallIn,是因为 Hilt 内部已经做了处理能够根据被注⼊对象确定 Scope ,⽐如 Activity 的注⼊实例默认 Scope 就是 ActivityComponent。
定义 @EnterPoint 之后,我们可以通过 EnterPointAccessors 的静态⽅法获取对应实例,⽐如 LogContentProvider 中的
getLogDao(appContext: Context) 的实现:
class LogsContentProvider:ContentProvider(){
...
private fun getLogDao(appContext: Context): LogDao {
val hiltEntryPoint = EntryPointAccessors.fromApplication(
appContext,
LogsContentProviderEntryPoint::class.java
单向好友什么意思)
return hiltEntryPoint.logDao()
}
如何写请假条
}芬芳满堂
EnterPointAccessors 提供了四个静态⽅法,分别⽤来从不同 Scope 中获取⽰例,传⼊的第⼀个参数需要与我们在 @InstallIn 中指定的Scope 相匹配,否则将⽆法正确获取实例。例⼦中我们将 LogDao 注册到 ApplicationScope ,所以我们使⽤ fromApplication 获取实例。