Jetpack Hilt 的 @EnterPoint 注解使用介绍
Posted fundroid_方卓
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jetpack 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 = "com.example.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 exposes 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>?,
selection: String?,
selectionArgs: 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.selectAllLogsCursor()
else
logDao.selectLogById(ContentUris.parseId(uri))
cursor?.setNotificationUri(appContext.contentResolver, uri)
cursor
else
throw IllegalArgumentException("Unknown URI: $uri")
如上,LogsContentProvider 用来从数据库查新日志,我们使用 Room 定义 LogDao,用来对数据库进行 query
@Dao
interface LogDao
...
@Query("SELECT * FROM logs ORDER BY id DESC")
fun selectAllLogsCursor(): Cursor
@Query("SELECT * FROM logs WHERE id = :id")
fun selectLogById(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
获取实例。
以上是关于Jetpack Hilt 的 @EnterPoint 注解使用介绍的主要内容,如果未能解决你的问题,请参考以下文章
#yyds干货盘点# JetPack | Hilt-依赖注入框架上手指南