Hilt与Dagger为何需要对Activity和Fragment进行依赖注入?
嘿,完全不用抱歉——从Dagger转到Hilt的时候,很多人都会有这样的疑问,毕竟我们已经习惯了Dagger那套写法😉。其实Hilt本质是Dagger的Android专属封装,它针对Activity、Fragment这类Android组件的注入做了大量优化,核心优势主要体现在这几个方面:
1. 彻底砍掉冗余样板代码
在Dagger里,要给Activity做注入,你得:
- 让Application实现
HasActivityInjector接口,还要提供DispatchingAndroidInjector<Activity>的实例 - 在自定义的Component里添加
void inject(YourActivity activity)方法 - 最后在Activity的
onCreate里调用AndroidInjection.inject(this)
而Hilt只需要两步:
- 给你的Activity加上
@AndroidEntryPoint注解 - 直接在Activity里用
@Inject标注需要注入的依赖
比如对比代码:
Dagger写法
// Application类 class MyApp : Application(), HasActivityInjector { @Inject lateinit var dispatchingActivityInjector: DispatchingAndroidInjector<Activity> override fun activityInjector(): AndroidInjector<Activity> = dispatchingActivityInjector override fun onCreate() { super.onCreate() DaggerAppComponent.create().inject(this) } } // Activity类 class MainActivity : AppCompatActivity() { @Inject lateinit var myRepository: MyRepository override fun onCreate(savedInstanceState: Bundle?) { AndroidInjection.inject(this) super.onCreate(savedInstanceState) } }
Hilt写法
// Application类(只需要加@HiltAndroidApp) @HiltAndroidApp class MyApp : Application() // Activity类 @AndroidEntryPoint class MainActivity : AppCompatActivity() { @Inject lateinit var myRepository: MyRepository override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 不用手动调用注入! } }
省掉的代码可不是一星半点,而且不用再维护那些HasXXXInjector接口和对应的注入器,大大降低了代码复杂度。
2. 自动绑定Android组件生命周期
Hilt会自动根据Android组件的生命周期来触发注入:
- Activity的注入会在
super.onCreate()之前完成 - Fragment的注入会在
onAttach()之后、onCreate()之前完成
你完全不用操心注入时机的问题,避免了Dagger里可能因为手动调用AndroidInjection.inject(this)的时机不对(比如放在super.onCreate()之后)导致的空指针异常。
3. 标准化的组件层次结构
Dagger里你需要自己设计Component的依赖关系(比如ActivityComponent依赖ApplicationComponent),很容易出现组件结构混乱的情况。而Hilt已经内置了一套符合Android生命周期的标准组件层次:
ApplicationComponent(对应Application生命周期)ActivityComponent(对应Activity生命周期)FragmentComponent(对应Fragment生命周期)- 还有ViewModelComponent、ServiceComponent等
这些组件之间的依赖关系已经帮你处理好了,比如ActivityComponent会自动继承ApplicationComponent的依赖,你不用再手动去定义Component的dependencies属性,直接用就行。
4. 原生Android类的便捷注入
Hilt直接支持注入Context、Activity、Fragment这些Android原生类,不用自己写@Provides方法。比如:
@AndroidEntryPoint class MainFragment : Fragment() { @Inject lateinit var appContext: Context @Inject lateinit var hostActivity: MainActivity // 直接用就行,不用额外配置 }
在Dagger里要实现这个,你得在Component里添加对应的方法,或者写@Provides来提供这些实例,麻烦得多。
5. 与Jetpack组件无缝集成
Hilt和Jetpack的ViewModel、WorkManager等组件集成非常顺畅。比如要给ViewModel注入依赖,只需要给ViewModel加@HiltViewModel注解,然后在Activity/Fragment里用by viewModels()就能拿到注入好的ViewModel:
@HiltViewModel class MainViewModel @Inject constructor( private val myRepository: MyRepository ) : ViewModel() { // ... } // 在Activity里使用 @AndroidEntryPoint class MainActivity : AppCompatActivity() { private val viewModel: MainViewModel by viewModels() }
而Dagger里要实现ViewModel的注入,你得自己写ViewModelFactory,还要在Component里绑定Factory,步骤繁琐得多。
总的来说,Hilt就是把Android开发中最常用的依赖注入场景做了标准化封装,让我们不用再重复造轮子,把精力放在业务逻辑上,而不是维护Dagger的各种模板代码。
内容的提问来源于stack exchange,提问作者Karl Einstein

