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 实例化,并允许构造函数注入依赖
关键原理: Dagger 编译时通过这三个注解生成组件类。例如 @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
}
注意:SystemUI 中存在多个 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 的 Activity
  • NotificationViewModel_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 的依赖注入链路与组件层级:

Hilt 注入链路与组件层级 Hilt 注入链路与组件层级 @HiltAndroidApp(Application) SingletonComponent 根组件 @AndroidEntryPoint(Activity) ActivityComponent 子组件 @AndroidEntryPoint(Fragment) FragmentComponent 子组件 @HiltViewModel(ViewModel) ViewModelComponent 桥梁 ViewModelProvider 注入依赖传递路径 • @HiltAndroidApp → 创建 SingletonComponent(Application 级别单例) • @AndroidEntryPoint → 创建 ActivityComponent / FragmentComponent,可获取 Singleton 作用域的依赖 • @HiltViewModel → 通过 ViewModelComponent 将 ViewModel 与 Fragment/Activity 生命周期绑定

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。