开发者

Android Hilt依赖注入的实现浅析

目录
  • 什么是依赖注入
  • 使用依赖注入的好处
  • Hilt 中常用的预定义限定符
    • @HiltandroidApp
    • @AndroidEntryPoint
    • @Module
    • @InstallIn
    • @Provides
    • @Inject
    • @HiltViewModel
  • Hilt的使用
    • 依赖
    • 建立实体类
    • 添加Hilt入口
    • 提供对象
    • 获取对象
  • 应用与ViewModel中
    • 使用
  • 总结

    什么是依赖注入

    首先,某个类的成员变量称为依赖,如若此变量想要实例化引用其类的方法,可以通过构造函数传参或者通过某个方法获取对象,此等通过外部方法获取对象实例的称为依赖注入;而依赖注入又可以简单分为手动注入和自动注入两种方式;Hilt就是基于Dagger进行场景化优化的一个依赖注入库,Hilt是Google专门为Android平台打造的一个依赖注入库,在使用上极大程度进行啦简化(与dagger相比)

    使用依赖注入的好处

    Google文档中介绍的优势如下:

    • 重用代码
    • 易于重构
    • 易于测试

    简单来说,在开发中某些内容需要进行层层手动调用,而且需要手动进行实例化;对于Hilt而言,它可以自动进行依赖注入,并且为项目中的每个 Android 类提供容器并自动管理其生命周期;某些需要全局使用的数据,可以通过Hilt进行共享,从而简化代码

    Hilt 中常用的预定义限定符

    @HiltAndroidApp

    所有使用 Hilt 的应用都必须包含一个带有 js@HiltAndroidApp 注解的 Application 类。@HiltAndroidApp 会触发 Hilt 的代码生成操作,生成的代码包括应用的一个基类,该基类充当应用级依赖项容器,记得此Application类要在清单文件中进行引用

    @HiltAndroidApp
    class App : Application() { ... }
    

    @AndroidEntryPoint

    如果某个Activity要使用Hilt依赖注入,就必须给Activity添加@AndroidEntryPoint注解,同理Activity中的某个Fragment也需要使用,也必须添加@AndroidEntryPoint注解;

    目前Hilt 支持以下 Android 类:

    • Application(通过使用 @HiltAndroidApp)
    • ViewModel(通过使用 @HiltViewModel)
    • Activity
    • Fragment
    • View
    • Service
    • BroadcastReceiver
    @AndroidEntryPoint
    class MainActivity : ComponentActivity() {...}
    

    @Module

    Hilt带有一个模块的类,使用@Module注解的类,它会告知Hilt,它提供了哪些实例,通常和@Provider搭配使用,必须通过@InstallIn注解为其添加作用域

    @InstallIn

    对于您可以从中执行字段注入的每个 Android 类,都有一个关联的 Hilt 组件,您可以在 @InstallIn 注解中引用该组件。每个 Hilt 组件负责将其绑定注入相应的 Android 类。

    Android 组件默认绑定
    SingletonComponentApplication
    ActivityRetainedComponentApplication
    ViewModelComponentSavedStateHandle
    ActivityComponentApplication 和 Activity
    FragmentComponentApplication、Activity 和 Fragment
    ViewComponentApplication、Activity 和 View
    ViewWithFragmentComponentApplication、Activity、Fragment 和 View
    ServiceComponentApplication 和 Service
    @Module
    @InstallIn(SingletonComponent::class)
    object AppModule {...}
    

    @Provides

    如果想要让Hilt知道,提供了哪些实例对象,可以使用@Provides进行注解,以下提供啦一个数据库实例,并且作用域是全局单例

        @Provides
        @Singleton
        fun providerAccountBean():AccountBean{
            return AccountBean("FranzLiszt","123456")
        }
    

    @Inject

    如果想要使用Hilt自动进行啦依赖注入的对象,可以使用@Inject注解进行调用;如下,无需进行实例化,它会自动引用providerAccountBean()提供的对象

    @Inject lateinit var bean: AccountBean

    @HiltViewModel

    通过名称就可以了解,它需要与ViewModel类联合使用,作用于ViewModel上;如下,与@Inject结合使用,在构造函数引用啦上述Hilt提供的对象

    @HiltViewModel
    class AccountViewModel @Inject constructor(private val bean: AccountBean):ViewModel() {...}
    

    Hilt的使用

    依赖

    第一步:在project/build.gradle中添加如下代码

    plugins {

        ...

        id 'com.google.dagger.hilt.android' version '2.44' apply false

    }

    第二步:在app/build.gradle中添加如下代码

    plugins {

        ...

        id 'kotlin-kapt'

        id 'dagger.hilt.android.plugin'

    }

    第三步:在app/build.gradle中添加如下代码

       //Dagger - Hilt

        implementation("com.google.dagger:hilt-android:2.44")

        kapt("com.google.dagger:hilt-android-compiler:2.44")

        // Compose dependencies

        implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.4.0-beta01"

        implementation "androidx.hilt:hilt-navigation-compose:1.0.0-alpha03"

    第四步:在aphppp/build.gradle中添加如下代码

    android{

    ...

     compileOptions {

            sourceCompatibility JavaVersion.VERSION_1_8

            targetCompatibility JavaVersion.VERSION_1_8

        }

    }

    建立实体类

    data class AccountBean(var username:String,var password:String)

    添加Hilt入口

    @HiltAndroidApp
    class APP:Application() {}
    

    提供对象

    此处作为用例,只是简单写一个测试用例,在函数中可以编写复杂的程序,并不会影响程序性能,在程序初始化编译时会耗时一丢丢。一下提供啦单例AccountBean对象

    @Module
    @InstallIn(SingletonComponent::class)
    object AppModule {
        @Projsvides
        @Singleton
        fun providerAccountBean():AccountBean{
            return AccountBean("FranzLiszt","123456")
        }
    }
    

    获取对象

    给Activity添加HiltAndroidEntryPoint注解,然后可以通过Inject注解获取上面providerAccountBean方法提供的对象

    @AndroidEntryPoint
    class MainActivity : ComponentActivity() {
        @Inject lateinit var bean: AccountBean
        ...
        }
    

    然后就可以直接进行对象引用

      @Composable
        fun showAccountInfo() {
            Column(
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Text(text = bean.username)
                Spacer(modifier = Modifier.height(20.dp))
                Text(text = bean.password)
            }
        }
    

    应用与ViewModel中

    在ViewModel中使用HiltViewModel注解,然后就可以使用Inject注解获取Hilt自动注入依赖的对象

    @HiltViewModel
    class AccountViewModel @Inject constructor(private val bean: AccountBean):ViewModel() {...}
    

    定义两个具有状态的成员变量,其中AccountState是一个数据类,具有text和hint两个成员变量

    private val _usernameState =python mutableStateOf(AccountState(
            hint = "input username"
        ))
        val usernameState:State<AccountState> = _usernameState
        private val _passwordState = mutableStateOf(AccountState(
            hint = android"input password"
        ))
        val passwordState:State<AccountState> = _passwordState
    

    在ViewModel初始化函数中,将Hilt提供的对象的值赋值给VM中的两个状态变量

    init {
            _usernameState.value = usernameState.value.copy(text = bean.username)
            _passwordState.value = passwordState.value.copy(text = bean.password)
        }
    

    通过外部事件进行对应处理,外部输入框不断进行值修改,此处同步给VM中的状态变量

       fun onEvent(event: AccountEvent){
            when(event){
                is AccountEvent.ChangeUsername ->{
                    _usernameState.value = usernameState.value.copy(text = event.value)
                }
                is AccountEvent.ChangePassword ->{
                    _passwordState.value = passwordState.value.copy(text = event.value)
                }
            }
        }
    

    使用

    此处直接获取ViewModel的两个成员变量值,然后与两个输入框进行绑定,通过监听输入框的onValueChange方法,当其值不断修改时,然后调用VM中的onEvent方法,然后修改VM中的状态内容,由于输入框绑定了VM的状态变量,然后状态变量值改变后,相对应的UI界面会进行重组

        @Composable
        fun showAccountInfo (viewModel: AccountViewModel = hiltViewModel()){
            val username = viewModel.usernameState.value
            val password = viewModel.passwordState.value
            Column(
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                TextField(
                    value = username.text,
                    placeholder = { Text(text = username.hint)},
                    onValueChange = {
                        viewModel.onEvent(AccountEvent.ChangeUsername(it))
                    }
                )
                Spacer(modifier = Modifier.height(20.dp))
                TextField(
                    value = password.text,
                    placeholder = { Text(text = password.hint)},
                    onValueChange = {
                        viewModel.onEvent(AccountEvent.ChangePassword(it))
                    }
                )
            }
        }
    

    总结

    上述的俩个测例,只是使用Hilt提供的便利的冰山一角;Hilt使用起来很方便,而去可以提高代码结构,省去不必要的代码;其中Koin依赖注入库也备受好评,虽然我没有使用过,因为Google推Hilt,就首先入手啦;在性能上,我看了一些其他文章上介绍,大差不差的,所有根据自己需要进行选择。

    到此这篇关于Android Hilt依赖注入的实现浅析的文章就介绍到这了,更多相关Android Hilt依赖注入内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多开发者_开发入门支持我们!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜