携手创作,共同成长!这是我参与「日新计划 8 月更文挑战」的第13天,点击查看活动详情

为什么要运用Hilt依靠注入

之前有写过一些文章 Hilt与Koin的对比,和 Android开发中Hilt的常用场景。看起来是十分简略与实用了,可是会引起一些同学的疑问?

为什么要运用依靠注入?直接new目标不香吗?为什么要把简略的问题杂乱化?

你是不是在炫技,是不是像装13?

这还真不是,假如说我运用的Dagger2,还真是炫技,NB啊。Dagger的坑也是真的多,能在大项目中把Dagger用好,那还真是牛,可是咱们现在都用Hilt了有什么可装的,运用是真的简略,都是一些场景化的东西,一些固定用法。没必要没必要。

回归正题,为什么要运用依靠注入?哪种情况下引荐运用依靠注入?就算要用依靠注入,为什么依靠注入引荐运用Hilt?

一、主动办理(灵活与解耦)

首要不是说咱们写项目就必定要运用依靠注入,假如咱们的项目不是大项目,总共就5、6个,10多个页面,你没必要上依靠注入结构,假如是大项目,分模块,分组件,多人协同开发的,而且或许依靠的目标很杂乱,或者说套娃似的目标依靠,那么运用Hilt就十分便利。不同模块/组件的开发人员直接在他自己的组件/模块下定义好目标的供给方法,另一边直接用即可,无需联系依靠的杂乱度,和完成的逻辑。

咱们先看看一些杂乱的嵌套依靠,比方咱们来一个三层套娃的依靠:

@Singleton
class UserServer @Inject constructor(private val userDao: UserDao) {
    fun testUser() {
        YYLogUtils.w(userDao.printUser())
        toast(userDao.printUser())
    }
    fun getDaoContent():String{
        return userDao.printUser()
    }
}
@Singleton
class UserDao @Inject constructor(private val user: UserBean) {
    fun printUser(): String {
        return user.toString()
    }
}
data class UserBean(
    val name: String,
    val age: Int,
    val gender: Int,
    val languages: List<String>
)

其他三个类都是有必要了,其实也就多了一个这个类,供给UserBean目标

@Module
@InstallIn(SingletonComponent::class)
class Demo10DIModule {
    @Singleton
    @Provides
    fun provideUser(): UserBean {
        return UserBean("newki", 18, 1, listOf("中文", "英文"))
    }
}

运用:

@AndroidEntryPoint
class Demo10DIActivity : BaseVMActivity() {
    @Inject
    lateinit var userServer: UserServer
    override fun getLayoutIdRes(): Int = R.layout.activity_demo10_di
    override fun init() {
        findViewById<Button>(R.id.btn_01).click {
            YYLogUtils.w(userServer.toString())
            userServer.testUser()
        }
    }

假如不运用Hilt,自己new目标也能完成

class Demo10DIActivity : BaseVMActivity() {
    lateinit var userServer: UserServer
    override fun getLayoutIdRes(): Int = R.layout.activity_demo10_di
    override fun init() {
        //自己new三个目标
         userServer = UserServer(UserDao(UserBean("newki", 18, 1, listOf("中文", "英文"))))
        findViewById<Button>(R.id.btn_01).click {
            YYLogUtils.w(userServer.toString())
            userServer.testUser()
        }
    }

这样new出来的目标,且不说生命周期是跟随页面的,无法保持单例,咱们就说假如需求变了,UseDao中需要UserBean和UserProfile2个目标了,假如你是new目标,那么就要处处修正,假如是Hilt的方法,咱们就只需要修正UserDao目标的构造即可

@Singleton
class UserDao @Inject constructor(private val user: UserBean,private val profile:UserProfile) {
    fun printUser(): String {
        return user.toString()
    }
}

以上仅仅举个简略比方,构建一个目标,还要构建一堆其他的目标,而且其他目标的构建相同杂乱,而且有必要按顺序构建,而且需要的目标的生命周期都不相同,有些生命周期或许和Activity相同,有些或许是单例,所以在构建的时分还要考虑目标声明周期,考虑目标的来历。

特别是在大型项目中很痛苦,由于项目不是一个人写的,咱们协同合作开发,看他人的代码也和看天书相同,并不知道搭档的目标是怎样创立的,假如一个目标的构建方法发生改变,会影响整个的构建过程以及所相关的代码,牵一发而动全身。

这个时分依靠注入结构就派上用场了,咱们只用专心于怎样完成功能,目标的依靠联系和生命周期,都让它来帮咱们办理,一个Inject,它会按照依靠联系帮咱们注入咱们需要的目标,而且它会办理好每个目标的生命周期,在生命周期还没完毕的情况下是不会重复new的。

所以Hilt依靠注入十分适合大项目,小项目开发者由于项目杂乱度低,没遇到这些问题,所以不会了解为什么要用Hilt依靠注入,发出疑问,为什么要让简略的new目标搞这么杂乱。

二、生命周期操控

这里说目标的生命周期,其实便是在必定效果域的生命周期,假如仅仅说单例有点太浅薄,能够说是是在必定规模内的单例。

咱们直接new目标是无法操控生命周期的,除非咱们运用大局单例的目标,而经过Hilt依靠注入咱们能够很便利的完成目标的生命周期的操控。

比方咱们一般目标的快速注入方法,直接注解Singleton就标注的是大局规模单例

@Singleton
class UserServer @Inject constructor(private val userDao: UserDao) {
    fun testUser() {
        YYLogUtils.w(userDao.printUser())
        toast(userDao.printUser())
    }
    fun getDaoContent():String{
        return userDao.printUser()
    }
}

另一种用法是咱们运用Module的方法定义依靠注入,那么运用SingletonComponent + Singleton 相同是大局规模单例的意思

@Module
@InstallIn(SingletonComponent::class)
class Demo10DIModule {
    @Singleton
    @Provides
    fun provideUser(): UserBean {
        return UserBean("newki", 18, 1, listOf("中文", "英文"))
    }
}

假如咱们想Activity内的单例,咱们运用ActivityComponent + ActivityScoped 便是Activity规模的单例。

@Module
@InstallIn(ActivityComponent::class)
class Demo10DIModule {
    @ActivityScoped
    @Provides
    fun provideUser(): UserBean {
        return UserBean("newki", 18, 1, listOf("中文", "英文"))
    }
}

以上两种都是比较常用的效果域,其他的咱们还能保证Fragment内单例,View内部单例等等,用法都是相同的用法。

所以对依靠目标的生命周期操控也是Hilt很便利的一个特点,运用new目标是无法做到这一点的。

三、对比其他依靠注入

目前Android干流的也便是三种依靠注入 Dagger2 Hilt Koin。

之前比较过Koin,只能在Kotlin言语环境中运用。而且性能并不会好过Hilt。过错提示也不友好。

Dagger2不是不能用,17年18年的时分特别火,可是学习本钱很高,每次创立UI个依靠注入类还得mackproject,而且过错的提示也不友好,

不就new个对象的事,为什么要把简单的问题复杂化?为什么要使用Hilt依赖注入?看完就知道!

其实我17年就已经在运用Dagger2了,然后自己做了Demo与结构封装,后来做项目中并没有运用,一个是坑太多,一个是搭档不会用,学习本钱太高。也就抛弃运用Dagger2了。

而Hilt其实便是Daggert2的Android场景化的完成,内部对Dagger2进行了封装,在Android开发中运用Hilt愈加的简洁,学习本钱很低,过错提示友好。而且还对ViewModel都能够注入了哦。所以说它是专为Android开发而生。

关于注入的目标内存占用是否有优化的这一点,其实并没有文章或者官方的文档指出有内存优化这一点,仅我自己的测验来说,整个页面假如有多个注入目标和直接new目标比较,感觉注入的目标占用内存稍微少一点,不知道是不是测验的波动,我不了解,如有懂的大佬还望点拨一下。

总结

总结为什么要运用Hilt。

  1. 偷懒;主动办理,多目标的主动注入,万一有修正不需要到尸山中处处趴。
  2. 单例;让目标拥有生命周期,无需咱们自己手动单例创立,然后去手动刊出。
  3. 解耦;不需要处处引进我一些不需要的目标,特别是组件化的项目,另一个组件只管注入,在我的组件中我只管引证。

我觉得这是我运用Hilt最招引我的三个点,

所以说目前2022年了,依靠注入我引荐Hilt。关键运用简略,在Android的常用场景下我还做了一些 Demo, 总共就那么多固定的一些用法,之前我写过Demo掩盖Android开发大部分的运用场景, 有需要直接拿走即可,能够查看我之前的文章。

趁便说一句,这是国外程序员的必备面试技能,感觉比较国内的开发者老外的Android开发者特别喜欢运用Dagger2和Hilt,不少老项目都是用Dagger2的。

好了,本期内容如讲的不到位或讹夺的当地,希望同学们能够指出交流。

假如感觉本文对你有一点点点的启示,还望你能点赞支撑一下,你的支撑是我最大的动力。

Ok,这一期就此结束。

不就new个对象的事,为什么要把简单的问题复杂化?为什么要使用Hilt依赖注入?看完就知道!