3. Hilt 入门配置:@HiltAndroidApp、@AndroidEntryPoint、@HiltViewModel
SystemUI 作为系统级进程,依赖注入的初始化时机与组件挂载方式与普通应用不同。Hilt 通过三个核心注解建立了从 Application 到 ViewModel 的完整注入链路。本章从原理出发,逐步覆盖配置步骤、代码实现、调试验证及高频踩坑点。
3.1 核心注解职责与分层
| 注解 | 作用层次 | 职责 |
|---|---|---|
@HiltAndroidApp |
Application | 生成 Hilt 组件树的根节点(SingletonComponent),触发 Dagger 编译期的组件生成 |
@AndroidEntryPoint |
Activity / Fragment / Service / BroadcastReceiver / View | 将目标类标记为 Hilt 可注入容器,自动生成对应的 Hilt_ 子类 |
@HiltViewModel |
ViewModel | 配合 @AndroidEntryPoint 使 ViewModel 可被 Hilt 实例化,并允许构造函数注入依赖 |
@HiltAndroidApp 会生成 Hilt_SystemUIServiceApplication,它继承自原始 Application,并在 onCreate 中初始化 Dagger 容器。
3.2 配置步骤:从 Application 到 ViewModel
3.2.1 添加 Hilt Gradle 依赖
在模块级 build.gradle 中声明 Hilt 插件和依赖(SystemUI 通常使用 com.android.application 或 com.android.library 插件,但 Hilt 要求 Application 模块必须是 com.android.application):
// 根 build.gradle(或 setting.gradle)
plugins {
id 'com.google.dagger.hilt.android' version '2.51.1' apply false
}
// 模块 build.gradle
plugins {
id 'com.android.application'
id 'com.google.dagger.hilt.android'
}
dependencies {
implementation 'com.google.dagger:hilt-android:2.51.1'
kapt 'com.google.dagger:hilt-android-compiler:2.51.1'
implementation 'androidx.hilt:hilt-navigation-compose:1.2.0' // 若使用 Compose
}
build.gradle(如 packages/SystemUI、vendor/…)。必须确保 Application 子类所在模块启用了 Hilt 插件,且该模块不能是纯 library,否则 @HiltAndroidApp 无法生成入口组件。
3.2.2 标记 Application 类
// SystemUIServiceApplication.java
@HiltAndroidApp
public class SystemUIServiceApplication extends Application {
// Hilt 自动生成 Hilt_SystemUIServiceApplication
@Override
public void onCreate() {
super.onCreate();
// Dagger 容器在此方法被调用时已初始化
}
}
更新 AndroidManifest.xml 中的 <application android:name=".SystemUIServiceApplication" />。注意:如果原本有自定义 Application 并使用了 attachBaseContext,需在子类中保留。
3.2.3 标记 Activity / Fragment / Service
@AndroidEntryPoint
public class NotificationPanelActivity extends Activity {
@Inject
NotificationController mNotificationController; // 自动注入
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// mNotificationController 已可用
}
}
对于 Fragment:
@AndroidEntryPoint
public class QuickSettingsFragment extends Fragment {
@Inject
QSTileHost mQSTileHost;
}
3.2.4 标记 ViewModel
@HiltViewModel
public class NotificationViewModel extends ViewModel {
private final NotificationRepository repository;
@Inject
public NotificationViewModel(NotificationRepository repository) {
this.repository = repository;
}
}
在 Activity 或 Fragment 中通过 ViewModelProvider 获取时,Hilt 会自动填充依赖:
@AndroidEntryPoint
public class NotificationPanelActivity extends Activity {
private NotificationViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewModel = new ViewModelProvider(this).get(NotificationViewModel.class);
// 无需手动构造,Hilt 自动注入 repository
}
}
3.3 编译与调试
编译后检查 build/generated/source/kapt/ 目录下的生成文件,确认存在以下关键类:
Hilt_SystemUIServiceApplication—— 根组件入口Hilt_NotificationPanelActivity—— 对应标记了@AndroidEntryPoint的 ActivityNotificationViewModel_HiltModules—— 用于桥接 ViewModel 与 Hilt 组件
Application.onCreate() 中设置断点,观察 SingletonComponent 是否已实例化;通过 Android Studio 的 Dagger 插件查看组件树是否包含所有 @Inject 构造。
3.4 常见错误与解决方案
| 错误现象 | 根因 | 解决 |
|---|---|---|
编译时 @HiltAndroidApp 报错:MissingBinding |
未添加 @Module 或 @Provides 提供依赖 |
检查所有 @Inject 构造的类是否具有所需依赖的提供者 |
运行时 NoSuchMethodError: Hilt_xxx.onCreate |
AndroidManifest 中 application name 未更新为 Hilt 生成的子类 | 确保 manifest 中使用 .SystemUIServiceApplication(Hilt 会动态替换) |
| ViewModel 中的依赖为 null | Fragment/Activity 未标记 @AndroidEntryPoint 或 ViewModel 未使用 @HiltViewModel |
确保宿主组件和 ViewModel 均正确标注 |
| 多模块下 component 冲突 | 多个 library 模块分别声明了 @HiltAndroidApp |
只能有一个 Application 级模块标记 @HiltAndroidApp,其他模块使用 @HiltAndroidEntryPoint |
3.5 Hilt 组件注入链路图
下图展示了从 Application 到 ViewModel 的依赖注入链路与组件层级:
3.6 性能与稳定性优化建议
- 懒加载: 对于非必需的依赖,使用
@LazyInject或Provider延迟初始化,避免 Application 启动时注入过多对象导致开机时间恶化。 - 组件作用域: 尽量将 SystemUI 中的全局服务(如
NotificationManagerService的本地代理)标记为@Singleton,避免 Activity 范围内重复创建。 - 避免 Circular Dependency: SystemUI 组件间引用关系复杂,借助 Dagger 的编译时检测,发现循环依赖后使用
Provider<T>或重构模块层级。 - 增量编译: 配置
kapt { useBuildCache = true }以及将 Hilt Gradle 插件升级到最新,减少每次改动后的编译时间。
3.7 本机部署验证
编译后 push APK 至设备,观察 logcat 过滤 dagger.hilt:
// 验证 @HiltAndroidApp 初始化
adb logcat -s "dagger.hilt" | grep "Hilt_SystemUIServiceApplication"
// 预期输出:D/Hilt_SystemUIServiceApplication: Hilt Application started.
// 验证 Activity 注入
adb logcat -s "NotificationPanelActivity" | grep "mNotificationController"
// 检查是否有 NullPointerException 或缺失绑定异常
若出现 java.lang.IllegalStateException: Hilt application is not initialized,检查是否继承了 Hilt_Application 或是否在 manifest 中正确声明了 SystemUIServiceApplication。