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-依赖注入框架上手指南

Jetpack架构组件库:Hilt

Jetpack架构组件库:Hilt

Hilt 稳定版发布 | 更便捷的 Android 依赖项注入

Hilt 介绍 | MAD Skills

Android Compose 新闻AppViewModelHlit数据流