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 获取实例。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Jetpack Compose for Desktop 中使用 JNI(Java Native Interface)可以让你与本地代码进行交互,调用 C/C++ 函数或访问本地库。以下是使用 JNI 在 Jetpack Compose for Desktop 中进行 JNI 开发的基本步骤: 1. 创建本地代码库:首先,你需要使用 C/C++ 编写本地代码库。可以使用你喜欢的 C/C++ 编译器将代码编译成动态链接库(.so 或 .dll 文件)。 2. 创建 Java 接口:在你的 Jetpack Compose for Desktop 项目中,创建一个 Java 接口来声明与本地代码库交互的函数。这个接口将作为 Java 和本地代码之间的桥梁。 3. 加载本地库:在你的 Jetpack Compose for Desktop 项目中,使用 `System.loadLibrary()` 或 `System.load()` 方法加载你的本地库。 4. 实现 Java 接口:创建一个 Java 类来实现你在第二步创建的 Java 接口。在这个类中,使用 `native` 关键字标记与本地代码库交互的函数。 5. 生成头文件:使用 `javac -h` 命令生成头文件(.h 文件)。这个命令会根据你在第二步创建的 Java 接口自动生成对应的头文件。 6. 实现本地代码:使用你喜欢的 C/C++ 编辑器打开生成的头文件,并实现其中声明的函数。确保函数签名和参数类型与 Java 接口中的一致。 7. 编译本地代码:使用你喜欢的 C/C++ 编译器编译你的本地代码,并生成动态链接库文件。 8. 调用本地函数:在你的 Jetpack Compose for Desktop 项目中,可以通过调用你在第二步创建的 Java 接口实现的函数来调用本地代码。 需要注意的是,JNI 开发需要一定的 C/C++ 编程经验,以及对 Java 和本地代码交互的机制有一定的了解。在使用 JNI 进行开发时,还需要注意内存管理和线程安全性等问题。确保在使用完本地资源后正确释放它们,以避免内存泄漏或其他问题的发生。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fundroid

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值