Hilt - 组件化的实现及Navigation在组件化中的应用

556 阅读26分钟

使用Hilt实现组件化的基本内容

1. Hilt 核心注解说明 📝

graph TD
    A[HiltAndroidApp] --> B[应用级注解]
    C[AndroidEntryPoint] --> D[组件级注解]
    E[Module] --> F[模块级注解]
    G[Inject] --> H[注入点注解]
    I[Provides] --> J[提供者注解]
    K[Singleton] --> L[作用域注解]

2. 注解详细说明 📌

// 1. @HiltAndroidApp
// 作用:应用程序入口,初始化Hilt
@HiltAndroidApp
class MyApplication : Application()

// 2. @AndroidEntryPoint
// 作用:标记可以接收依赖注入的Android组件
@AndroidEntryPoint
class MainActivity : AppCompatActivity()

// 3. @Module
// 作用:定义依赖提供者模块
@Module
@InstallIn(SingletonComponent::class)
object AppModule

// 4. @InstallIn
// 作用:指定模块安装的组件范围
@InstallIn(SingletonComponent::class)  // 应用级别
@InstallIn(ActivityComponent::class)   // Activity级别
@InstallIn(FragmentComponent::class)   // Fragment级别

// 5. @Inject
// 作用:标记注入点或构造函数
class Repository @Inject constructor()

// 6. @Provides
// 作用:在模块中提供依赖实例
@Provides
fun provideDatabase(): Database

// 7. @Singleton
// 作用:标记单例作用域
@Singleton
class UserRepository

// 8. @HiltViewModel
// 作用:标记ViewModel类
@HiltViewModel
class MainViewModel @Inject constructor()

3. Hilt 组件层次 🏗️

graph TD
    A[SingletonComponent] --> B[ActivityRetainedComponent]
    B --> C[ActivityComponent]
    C --> D[FragmentComponent]
    C --> E[ViewComponent]
    D --> F[ViewWithFragmentComponent]
    
    style A fill:#f9f,stroke:#333
    style B fill:#bbf,stroke:#333
    style C fill:#bfb,stroke:#333
    style D fill:#fbf,stroke:#333

4. 作用域注解对应关系 🎯

// 组件与作用域对应关系
SingletonComponent::class      -> @Singleton
ActivityRetainedComponent::class -> @ActivityRetainedScoped
ActivityComponent::class      -> @ActivityScoped
FragmentComponent::class      -> @FragmentScoped
ViewComponent::class         -> @ViewScoped
ViewWithFragmentComponent::class -> @ViewScoped
ServiceComponent::class      -> @ServiceScoped

5. 完整使用流程 🔄

sequenceDiagram
    participant App as Application
    participant Module as Hilt Module
    participant Component as Android Component
    participant ViewModel as ViewModel
    
    App->>App: @HiltAndroidApp
    App->>Module: @Module @InstallIn
    Module->>Module: @Provides/@Singleton
    Component->>Component: @AndroidEntryPoint
    Component->>ViewModel: @HiltViewModel
    ViewModel->>Module: @Inject

6. 实际使用示例 📱

// 1. 应用入口
@HiltAndroidApp
class MyApplication : Application()

// 2. 定义模块
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    // 提供网络客户端
    @Provides
    @Singleton
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder().build()
    }
    
    // 提供Retrofit实例
    @Provides
    @Singleton
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .client(okHttpClient)
            .baseUrl("https://api.example.com")
            .build()
    }
}

// 3. 使用依赖注入
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    // 注入ViewModel
    private val viewModel: MainViewModel by viewModels()
    
    // 注入其他依赖
    @Inject
    lateinit var repository: UserRepository
}

// 4. ViewModel注入
@HiltViewModel
class MainViewModel @Inject constructor(
    private val repository: UserRepository,
    @ApplicationContext private val context: Context
) : ViewModel()

7. 注解功能总结表 📊

注解作用使用位置
@HiltAndroidApp初始化HiltApplication类
@AndroidEntryPoint启用依赖注入Android组件类
@Module定义依赖提供者模块类
@InstallIn指定组件范围模块类
@Inject标记注入点构造函数/字段
@Provides提供依赖实例模块方法
@Singleton单例作用域类/提供方法
@HiltViewModelViewModel注入ViewModel类

8. 使用流程总结 🌟

  1. 初始化阶段
graph LR
    A[添加Hilt依赖] --> B[配置Application]
    B --> C[创建Module]
    C --> D[定义组件]
  1. 注入阶段
graph LR
    A[标记注入点] --> B[提供依赖]
    B --> C[使用依赖]
    C --> D[管理生命周期]
  1. 使用建议
  • 合理规划模块结构
  • 注意作用域范围
  • 避免循环依赖
  • 保持接口简洁
  • 合理使用限定符

Hilt 通过这些注解系统,实现了一个完整的依赖注入框架,大大简化了Android应用的依赖管理。

Hilt在Android组件化中的完整注解和依赖流程

graph TD
    A[Application Module<br>'dagger.hilt.android.plugin'] --> B[Hilt Application<br>HiltAndroidApp]
    
    B --> C{Feature Modules<br>各功能模块}
    
    C --> D[Login Module<br>Module<br>InstallIn]
    C --> E[Home Module<br>Module<br>InstallIn]
    C --> F[Profile Module<br>Module<br>InstallIn]
    
    D --> G[LoginComponent<br>Module<br>InstallIn<br>Provides]
    E --> H[HomeComponent<br>Module<br>InstallIn<br>Provides]
    F --> I[ProfileComponent<br>Module<br>InstallIn<br>Provides]
    
    G --> J[LoginRepository<br>Inject<br>Singleton]
    G --> K[LoginViewModel<br>HiltViewModel<br>Inject]
    H --> L[HomeRepository<br>Inject<br>Singleton]
    H --> M[HomeViewModel<br>HiltViewModel<br>Inject]
    
    J --> N[Activity/Fragment<br>AndroidEntryPoint]
    K --> N
    L --> O[Activity/Fragment<br>AndroidEntryPoint]
    M --> O

这个流程图展示了:

  1. 从顶层Application到底层使用处的完整依赖链
  2. 每个组件使用的关键注解
  3. 模块间的依赖关系
  4. 组件的层级结构

主要层级和注解:

  • 应用层:@HiltAndroidApp
  • 模块层:@Module, @InstallIn
  • 组件层:@Provides, @Singleton
  • 实现层:@Inject, @HiltViewModel
  • 使用层:@AndroidEntryPoint

让我详细解释这个图中每个组件对应的注解和含义:

1. Application层

// A[Application Module]
// 主应用模块,包含基础配置
build.gradle:
plugins {
    id 'dagger.hilt.android.plugin'
}

// B[Hilt Application]
@HiltAndroidApp  // 标记为Hilt应用入口
class MyApplication : Application() {
    // 初始化Hilt的应用程序类
}

2. Feature Modules层

// C{Feature Modules}
// 各个功能模块的容器,无具体注解
// 通常在build.gradle中配置:
plugins {
    id 'dagger.hilt.android.plugin'
}

// D[Login Module], E[Home Module], F[Profile Module]
// 各个功能模块,通常包含:
@InstallIn(SingletonComponent::class)  // 安装到单例组件
@Module                                // 标记为Hilt模块
object FeatureModule {
    // 模块配置
}

3. Component层

// G[LoginComponent], H[HomeComponent], I[ProfileComponent]
// 各个功能的组件定义

// 例如LoginComponent:
@InstallIn(ActivityComponent::class)  // 安装到Activity作用域
@Module
object LoginComponent {
    @Provides
    fun provideLoginRepository(): LoginRepository {
        // 提供Repository实例
    }
    
    @Provides
    fun provideLoginViewModel(): LoginViewModel {
        // 提供ViewModel实例
    }
}

4. Repository和ViewModel层

// J[LoginRepository]
interface LoginRepository {
    // 接口定义
}

@Singleton  // 标记为单例
class LoginRepositoryImpl @Inject constructor(
    // 构造注入
) : LoginRepository

// K[LoginViewModel]
@HiltViewModel  // 标记为Hilt管理的ViewModel
class LoginViewModel @Inject constructor(
    private val repository: LoginRepository
) : ViewModel()

// L[HomeRepository], M[HomeViewModel]同理

5. 使用处的注解

// 在Activity中使用
@AndroidEntryPoint  // 标记为注入点
class LoginActivity : AppCompatActivity() {
    @Inject
    lateinit var repository: LoginRepository  // 字段注入
    
    private val viewModel: LoginViewModel by viewModels()  // ViewModel注入
}

完整的依赖关系:

// 1. 应用层
@HiltAndroidApp// 2. 模块层
@Module + @InstallIn(SingletonComponent::class)// 3. 组件层
@Module + @InstallIn(ActivityComponent::class)// 4. 实现层
@Inject(构造注入)
@Singleton(单例标记)
@HiltViewModel(ViewModel注入)
↓
// 5. 使用层
@AndroidEntryPoint(注入点)
@Inject(字段注入)

常见作用域注解:

@Singleton               // 应用级单例
@ActivityScoped         // Activity级作用域
@FragmentScoped        // Fragment级作用域
@ViewModelScoped       // ViewModel级作用域
@ServiceScoped        // Service级作用域

这样的注解体系确保了:

  1. 依赖的正确注入
  2. 作用域的合理控制
  3. 组件的生命周期管理
  4. 模块间的解耦
  5. 测试的便利性

@Provider和@inject的区别

@Provides 的主要作用是告诉Hilt如何创建一个依赖实例。让我详细解释:

1. 基本用法

@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    // @Provides 告诉Hilt如何创建Repository实例
    @Provides
    fun provideRepository(): Repository {
        return RepositoryImpl()
    }
}

2. 创建第三方库实例

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    // 对于不能修改源码的第三方库,使用@Provides创建实例
    @Provides
    @Singleton
    fun provideRetrofit(): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com")
            .build()
    }
    
    @Provides
    @Singleton
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(LoggingInterceptor())
            .build()
    }
}

3. 依赖其他提供的实例

@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    // Retrofit依赖OkHttpClient
    @Provides
    fun provideRetrofit(
        okHttpClient: OkHttpClient  // 自动注入之前提供的OkHttpClient
    ): Retrofit {
        return Retrofit.Builder()
            .client(okHttpClient)
            .build()
    }
    
    // Api服务依赖Retrofit
    @Provides
    fun provideApiService(
        retrofit: Retrofit  // 自动注入之前提供的Retrofit
    ): ApiService {
        return retrofit.create(ApiService::class.java)
    }
}

4. @Provides vs @Inject

// 方式1:使用@Provides
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    @Provides
    fun provideRepository(): Repository {
        return RepositoryImpl()
    }
}

// 方式2:使用@Inject构造函数
class RepositoryImpl @Inject constructor() : Repository {
    // 实现...
}

// 区别:
// 1. @Provides适用于无法修改源码的类(如第三方库)
// 2. @Inject适用于自己的类,更简洁

5. 提供多个实例

@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {
    @Provides
    @Named("memory")  // 限定符
    fun provideMemoryDatabase(): Database {
        return MemoryDatabase()
    }
    
    @Provides
    @Named("disk")    // 限定符
    fun provideDiskDatabase(): Database {
        return DiskDatabase()
    }
}

// 使用时
class Repository @Inject constructor(
    @Named("memory") private val memoryDb: Database,
    @Named("disk") private val diskDb: Database
)

6. 条件提供

@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    @Provides
    fun provideDatabase(
        @ApplicationContext context: Context
    ): Database {
        return if (BuildConfig.DEBUG) {
            // 调试版本使用内存数据库
            MemoryDatabase()
        } else {
            // 正式版本使用磁盘数据库
            DiskDatabase(context)
        }
    }
}

7. 作用域控制

@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    // 单例作用域
    @Provides
    @Singleton
    fun provideSingletonRepository(): Repository {
        return RepositoryImpl()
    }
    
    // 默认作用域(每次注入都创建新实例)
    @Provides
    fun provideRepository(): Repository {
        return RepositoryImpl()
    }
}
  1. 实际应用场景
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    // 1. 网络相关
    @Provides
    @Singleton
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .client(okHttpClient)
            .build()
    }
    
    // 2. 数据库相关
    @Provides
    @Singleton
    fun provideDatabase(
        @ApplicationContext context: Context
    ): AppDatabase {
        return Room.databaseBuilder(
            context,
            AppDatabase::class.java,
            "app.db"
        ).build()
    }
    
    // 3. 工具类
    @Provides
    @Singleton
    fun provideSharedPreferences(
        @ApplicationContext context: Context
    ): SharedPreferences {
        return context.getSharedPreferences(
            "app_prefs",
            Context.MODE_PRIVATE
        )
    }
}

总结 @Provides 的主要用途:

  1. 创建第三方库实例
  2. 配置复杂对象
  3. 提供接口实现
  4. 条件创建实例
  5. 控制实例作用域
  6. 管理依赖关系

使用建议:

  1. 优先使用 @Inject 构造函数
  2. 第三方库使用 @Provides
  3. 需要特殊配置时使用 @Provides
  4. 合理使用作用域注解
  5. 注意依赖的顺序

使用Hilt来配置Android项目的组件化

1. 项目结构:

app/
├─ base/          // 基础库
├─ common/        // 公共库
├─ feature_a/     // 功能模块A
├─ feature_b/     // 功能模块B
└─ feature_c/     // 功能模块C

2. 基础配置:

Application配置:

// app模块
@HiltAndroidApp
class MyApplication : Application()

// build.gradle
plugins {
    id 'dagger.hilt.android.plugin'
    id 'kotlin-kapt'
}

3. 各模块依赖注入配置:

3.1基础模块(base):

// BaseModule.kt
@Module
@InstallIn(SingletonComponent::class)
object BaseModule {
    @Provides
    @Singleton
    fun provideDatabase(@ApplicationContext context: Context): AppDatabase {
        return Room.databaseBuilder(
            context,
            AppDatabase::class.java,
            "app_database"
        ).build()
    }
    
    @Provides
    @Singleton
    fun provideNetworkClient(): NetworkClient {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com")
            .build()
    }
}

3.2公共模块(common):

// CommonModule.kt
@Module
@InstallIn(SingletonComponent::class)
object CommonModule {
    @Provides
    @Singleton
    fun provideImageLoader(): ImageLoader {
        return GlideImageLoader()
    }
    
    @Provides
    @Singleton
    fun provideLogger(): Logger {
        return TimberLogger()
    }
}

4. 功能模块配置:

功能模块A:

// FeatureAModule.kt
@Module
@InstallIn(ViewModelComponent::class)
object FeatureAModule {
    @Provides
    fun provideFeatureARepository(
        database: AppDatabase,
        networkClient: NetworkClient
    ): FeatureARepository {
        return FeatureARepositoryImpl(database, networkClient)
    }
}

// FeatureAViewModel.kt
@HiltViewModel
class FeatureAViewModel @Inject constructor(
    private val repository: FeatureARepository,
    private val imageLoader: ImageLoader
) : ViewModel()
  1. 组件间通信:

使用EventBus:

@Module
@InstallIn(SingletonComponent::class)
object EventModule {
    @Provides
    @Singleton
    fun provideEventBus(): EventBus {
        return EventBus.getDefault()
    }
}
  1. 界面注入:

Activity注入:

@AndroidEntryPoint
class FeatureAActivity : AppCompatActivity() {
    @Inject
    lateinit var imageLoader: ImageLoader
    
    private val viewModel: FeatureAViewModel by viewModels()
}

Fragment注入:

@AndroidEntryPoint
class FeatureAFragment : Fragment() {
    @Inject
    lateinit var logger: Logger
    
    private val viewModel: FeatureAViewModel by viewModels()
}
  1. 组件化路由:
@Module
@InstallIn(SingletonComponent::class)
object RouterModule {
    @Provides
    @Singleton
    fun provideRouter(): Router {
        return Router.Builder()
            .addFeatureA()
            .addFeatureB()
            .addFeatureC()
            .build()
    }
}

// 使用路由
class Navigator @Inject constructor(
    private val router: Router
) {
    fun navigateToFeatureA() {
        router.navigate(Route.FEATURE_A)
    }
}
  1. 测试配置:
// 测试模块
@Module
@InstallIn(SingletonComponent::class)
object TestModule {
    @Provides
    @Singleton
    fun provideMockNetworkClient(): NetworkClient {
        return MockNetworkClient()
    }
}

// 测试用例
@HiltAndroidTest
class FeatureATest {
    @get:Rule
    val hiltRule = HiltAndroidRule(this)
    
    @Inject
    lateinit var repository: FeatureARepository
    
    @Test
    fun testFeatureA() {
        // 测试代码
    }
}
  1. 完整示例:

Application:

@HiltAndroidApp
class MyApplication : Application() {
    @Inject
    lateinit var router: Router
    
    @Inject
    lateinit var logger: Logger
    
    override fun onCreate() {
        super.onCreate()
        initializeComponents()
    }
    
    private fun initializeComponents() {
        router.init()
        logger.init()
    }
}

ViewModel:

@HiltViewModel
class MainViewModel @Inject constructor(
    private val repository: MainRepository,
    private val eventBus: EventBus,
    private val navigator: Navigator
) : ViewModel() {
    
    fun onFeatureAClick() {
        navigator.navigateToFeatureA()
    }
}

Repository:

class MainRepositoryImpl @Inject constructor(
    private val database: AppDatabase,
    private val networkClient: NetworkClient,
    private val logger: Logger
) : MainRepository {
    // 实现代码
}
  1. 最佳实践:

模块间依赖:

// build.gradle
dependencies {
    implementation project(':base')
    implementation project(':common')
    
    // 按需加载功能模块
    implementation project(':feature_a')
    implementation project(':feature_b')
}

使用Hilt实现组件化的关键点是:

  1. 合理划分模块
  2. 正确配置依赖注入
  3. 实现模块间通信
  4. 管理组件生命周期
  5. 便于测试和维护

Hilt框架中Module之间的依赖关系如何设置的

在Hilt中,主要通过 @InstallIn 和模块间的依赖注入来体现模块互相依赖关系。让我详细解释:

1. 基础依赖关系

// 1. 在common模块定义接口
interface LoginRepository {
    suspend fun login(username: String, password: String): Result
}

// 2. 在login模块实现
@Module
@InstallIn(SingletonComponent::class)  // 安装到单例组件,其他模块可以使用
object LoginModule {
    @Provides
    @Singleton
    fun provideLoginRepository(): LoginRepository {
        return LoginRepositoryImpl()
    }
}

// 3. 在其他模块使用
@HiltViewModel
class HomeViewModel @Inject constructor(
    private val loginRepository: LoginRepository  // 注入login模块的依赖
) : ViewModel()

2. 使用 @Binds 实现依赖

// 更推荐的方式是使用 @Binds
@Module
@InstallIn(SingletonComponent::class)
interface LoginModule {
    @Binds
    @Singleton
    fun bindLoginRepository(
        impl: LoginRepositoryImpl
    ): LoginRepository
}

3. 多模块依赖

// 1. 定义依赖模块
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    @Provides
    @Singleton
    fun provideRetrofit(): Retrofit = // ...
}

// 2. 使用其他模块的依赖
@Module
@InstallIn(SingletonComponent::class)
object LoginModule {
    @Provides
    fun provideLoginApi(
        retrofit: Retrofit  // 注入NetworkModule提供的依赖
    ): LoginApi = retrofit.create(LoginApi::class.java)
}

4. 包含其他模块

// 使用 includes 属性包含其他模块
@Module(
    includes = [
        NetworkModule::class,
        DatabaseModule::class
    ]
)
@InstallIn(SingletonComponent::class)
object AppModule {
    // ...
}

5. 作用域依赖

// 1. SingletonComponent(应用级别)
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    @Provides
    @Singleton
    fun provideDatabase(): AppDatabase = // ...
}

// 2. ViewModelComponent(ViewModel级别)
@Module
@InstallIn(ViewModelComponent::class)
object ViewModelModule {
    @Provides
    fun provideRepository(
        database: AppDatabase  // 可以注入SingletonComponent的依赖
    ): Repository = // ...
}

6. 组件依赖层级

SingletonComponent(顶层)
    ↓
ActivityRetainedComponent
    ↓
ActivityComponent
    ↓
FragmentComponent
    ↓
ViewComponent
    ↓
ViewWithFragmentComponent

7. 限定符区分依赖

// 1. 定义限定符
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class AuthInterceptorOkHttpClient

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class OtherInterceptorOkHttpClient

// 2. 提供不同的实现
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    @AuthInterceptorOkHttpClient
    @Provides
    @Singleton
    fun provideAuthOkHttpClient(): OkHttpClient = // ...

    @OtherInterceptorOkHttpClient
    @Provides
    @Singleton
    fun provideOtherOkHttpClient(): OkHttpClient = // ...
}

// 3. 在其他模块使用
@Module
@InstallIn(SingletonComponent::class)
object LoginModule {
    @Provides
    fun provideLoginApi(
        @AuthInterceptorOkHttpClient okHttpClient: OkHttpClient
    ): LoginApi = // ...
}

8. 测试替换依赖

@Module
@InstallIn(SingletonComponent::class)
object TestModule {
    @Provides
    @Singleton
    fun provideLoginRepository(): LoginRepository {
        return FakeLoginRepository()  // 测试时替换实现
    }
}

最佳实践:

1. 模块划分

// 1. 基础模块
@Module
@InstallIn(SingletonComponent::class)
object CoreModule

// 2. 功能模块
@Module
@InstallIn(SingletonComponent::class)
object FeatureModule

// 3. 应用模块
@Module(
    includes = [
        CoreModule::class,
        FeatureModule::class
    ]
)
@InstallIn(SingletonComponent::class)
object AppModule

2. 依赖注入规则

// 1. 单向依赖
Feature模块 → Core模块
Feature模块 ↛ Feature模块

// 2. 通过接口解耦
interface DataRepository
class DataRepositoryImpl @Inject constructor() : DataRepository

3. 作用域控制

// 1. 全局单例
@Singleton
@Provides
fun provideDatabase(): Database

// 2. 特定作用域
@ActivityScoped
@Provides
fun provideNavigator(): Navigator

总结:

  1. @InstallIn 定义依赖的作用域
  2. includes 属性包含其他模块
  3. 通过注入建立模块间依赖
  4. 使用限定符区分相同类型的依赖
  5. 遵循依赖注入的最佳实践

这样可以构建清晰、可维护的模块依赖关系。

组件化通信方案

1. LiveData + ViewModel:

// 共享ViewModel方式
@Module
@InstallIn(SingletonComponent::class)
object SharedViewModelModule {
    @Singleton
    @Provides
    fun provideSharedViewModel(): SharedViewModel {
        return SharedViewModel()
    }
}

// 使用
class FeatureAFragment {
    private val sharedViewModel: SharedViewModel by activityViewModels()
    
    fun sendMessage() {
        sharedViewModel.message.value = "Hello"
    }
}

2. Flow:

// 共享Flow
object MessageBus {
    private val _messageFlow = MutableSharedFlow<Message>()
    val messageFlow = _messageFlow.asSharedFlow()
    
    suspend fun sendMessage(message: Message) {
        _messageFlow.emit(message)
    }
}

// 使用
class FeatureAViewModel {
    init {
        viewModelScope.launch {
            MessageBus.messageFlow.collect { message ->
                // 处理消息
            }
        }
    }
}

3. 接口下沉:

// 定义接口在base模块
interface IFeatureA {
    fun getFeatureData(): String
    fun doSomething()
}

// 实现在feature模块
class FeatureAImpl : IFeatureA {
    override fun getFeatureData() = "data"
    override fun doSomething() {
        // 实现
    }
}

// 服务注册
@Module
@InstallIn(SingletonComponent::class)
object ServiceModule {
    @Provides
    @Singleton
    fun provideFeatureA(): IFeatureA = FeatureAImpl()
}

4. ServiceLoader:

// 定义服务接口
interface IFeatureService {
    fun doFeatureWork()
}

// 实现服务
@AutoService(IFeatureService::class)
class FeatureServiceImpl : IFeatureService {
    override fun doFeatureWork() {
        // 实现
    }
}

// 使用服务
val service = ServiceLoader.load(IFeatureService::class.java)
    .first()

5. ARouter:

// 路由注解
@Route(path = "/feature/main")
class FeatureActivity : Activity() {
    // 接收参数
    @Autowired
    lateinit var param: String
}

// 发起调用
ARouter.getInstance()
    .build("/feature/main")
    .withString("param", "data")
    .navigation()

6. StateFlow:

class SharedState {
    private val _state = MutableStateFlow<UIState>(UIState.Initial)
    val state = _state.asStateFlow()
    
    fun updateState(newState: UIState) {
        _state.value = newState
    }
}

// 使用
@HiltViewModel
class FeatureViewModel @Inject constructor(
    private val sharedState: SharedState
) : ViewModel() {
    init {
        viewModelScope.launch {
            sharedState.state.collect { state ->
                // 处理状态更新
            }
        }
    }
}

7. 广播:

// 本地广播
class LocalBroadcastManager {
    private val receiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            // 处理消息
        }
    }
    
    fun register(context: Context) {
        LocalBroadcastManager.getInstance(context)
            .registerReceiver(receiver, IntentFilter("action"))
    }
}

8. Channel:

object MessageChannel {
    private val channel = Channel<Message>()
    
    suspend fun send(message: Message) {
        channel.send(message)
    }
    
    suspend fun receive(): Message {
        return channel.receive()
    }
}

9. 组合使用示例:

class ModuleCommunicator @Inject constructor(
    private val sharedState: SharedState,
    private val messageChannel: MessageChannel,
    private val router: ARouter
) {
    // 状态共享
    fun updateState(state: UIState) {
        sharedState.updateState(state)
    }
    
    // 消息传递
    suspend fun sendMessage(message: Message) {
        messageChannel.send(message)
    }
    
    // 页面跳转
    fun navigateToFeature(params: Map<String, Any>) {
        router.build("/feature/main")
            .with(params)
            .navigation()
    }
}

各方案对比:

方案          优点                  缺点
LiveData     生命周期感知          范围局限
Flow        响应式、灵活           需要协程支持
接口下沉     简单直接              耦合较强
ServiceLoader 解耦合好             配置复杂
ARouter      功能完善              学习成本高
StateFlow    状态管理方便          需要协程支持
广播         使用简单              性能开销大
Channel      异步处理好            使用相对复杂

选择建议:

  1. 简单场景:LiveData或接口下沉
  2. 复杂场景:Flow或ARouter
  3. 状态共享:StateFlow
  4. 异步通信:Channel
  5. 可以组合使用多种方案

每种通信方案都有其适用场景,需要根据具体需求选择合适的方案!

通信流程图

组件间通信方案
│
├── 1. LiveData + ViewModel
│   ├── SharedViewModel (共享数据)
│   ├── LiveData (数据持有)
│   └── Observer (数据观察)
│
├── 2. Flow/StateFlow
│   ├── MutableSharedFlow (事件流)
│   ├── StateFlow (状态流)
│   └── collect (数据收集)
│
├── 3. 接口下沉
│   ├── IService (基础接口)
│   ├── ServiceImpl (实现类)
│   └── @Provides (依赖注入)
│
├── 4. ARouter
│   ├── @Route (路由注解)
│   ├── withXXX (参数传递)
│   └── navigation (页面跳转)
│
└── 5. ServiceLoader
    ├── Interface (服务接口)
    ├── @AutoService (服务注解)
    └── ServiceLoader.load (加载服务)

各方案对比表:

通信方案适用场景优点缺点
LiveData+ViewModel页面间通信生命周期感知作用域限制
Flow/StateFlow响应式通信灵活性强需要协程
接口下沉简单通信实现简单耦合较强
ARouter复杂路由功能完整配置复杂
ServiceLoader服务发现解耦合好性能较低

具体实现示例:

// 1. LiveData + ViewModel
class SharedViewModel : ViewModel() {
    private val _data = MutableLiveData<String>()
    val data: LiveData<String> = _data
    
    fun updateData(newData: String) {
        _data.value = newData
    }
}

// 2. Flow/StateFlow
object MessageBus {
    private val _messageFlow = MutableSharedFlow<Message>()
    val messageFlow = _messageFlow.asSharedFlow()
    
    suspend fun sendMessage(msg: Message) {
        _messageFlow.emit(msg)
    }
}

// 3. 接口下沉
// base模块
interface IUserService {
    fun getUserInfo(): User
}

// user模块
class UserServiceImpl : IUserService {
    override fun getUserInfo() = User()
}

// 4. ARouter
// 定义路由
@Route(path = "/user/detail")
class UserDetailActivity : Activity()

// 调用路由
ARouter.getInstance()
    .build("/user/detail")
    .withString("userId", "123")
    .navigation()

// 5. ServiceLoader
@AutoService(IService::class)
class ServiceImpl : IService {
    override fun doSomething() {}
}

通信流程示例:

模块A -> 模块B通信流程
│
├── 方案1: LiveData
│   ModuleA -> SharedViewModel -> LiveData.setValue -> ModuleB.observe
│
├── 方案2: Flow
│   ModuleA -> MessageBus.emit -> Flow -> ModuleB.collect
│
├── 方案3: 接口
│   ModuleA -> IService.call -> ServiceImpl -> ModuleB
│
└── 方案4: ARouter
    ModuleA -> ARouter.build -> navigation -> ModuleB

选择建议:

场景                推荐方案
├── 简单页面通信     LiveData+ViewModel
├── 复杂数据流       Flow/StateFlow
├── 模块间接口调用   接口下沉
├── 页面跳转        ARouter
└── 服务发现        ServiceLoader

注意事项:

1. 性能考虑
   ├── 避免频繁跨模块通信
   └── 合理使用缓存机制
   
2. 内存管理
   ├── 及时解除订阅
   └── 避免内存泄漏
   
3. 线程处理
   ├── 注意线程切换
   └── 异步操作处理

每种方案都有其适用场景,实际使用时可以根据需求组合使用多种方案!

组件化的流程总结图

Hilt组件化流程
│
├── 1. Application层
│   ├── @HiltAndroidApp
│   ├── 自定义Application
│   └── 生成Application_HiltComponents
│
├── 2. Module层
│   ├── @Module (依赖提供模块)
│   ├── @Provides/@Binds (提供依赖)
│   └── @InstallIn (指定作用域)
│
├── 3. Component作用域
│   ├── SingletonComponent (应用级别)
│   ├── ActivityComponent (Activity级别)
│   └── ViewModelComponent (ViewModel级别)
│
└── 4. 注入层
    ├── @AndroidEntryPoint (标记注入点)
    ├── @Inject (构造注入/属性注入)
    └── @HiltViewModel (ViewModel注入)
层级主要注解作用
Application层@HiltAndroidApp初始化Hilt,生成组件
Module层@Module, @Provides, @InstallIn提供依赖,指定作用域
Component层SingletonComponent等定义依赖作用域范围
注入层@AndroidEntryPoint, @Inject实现依赖注入
关键注解说明:
  1. 应用层注解:
@HiltAndroidApp
// 作用:初始化Hilt,生成应用级别组件
// 使用位置:Application类
  1. 模块注解:
@Module 
// 作用:声明依赖提供模块
// 使用位置:模块类

@InstallIn(XXXComponent::class)
// 作用:指定模块安装的组件范围
// 使用位置:Module类上

@Provides
// 作用:提供依赖实例的方法
// 使用位置:Module中的方法

@Binds
// 作用:绑定接口实现
// 使用位置:抽象Module中的抽象方法
  1. 作用域注解:
@Singleton
// 作用:应用级单例
// 使用位置:提供方法或类

@ActivityScoped
// 作用:Activity级别单例
// 使用位置:提供方法或类

@ViewModelScoped
// 作用:ViewModel级别单例
// 使用位置:提供方法或类
  1. 注入注解:
@AndroidEntryPoint
// 作用:标记可注入的Android组件
// 使用位置:Activity/Fragment/Service等

@Inject
// 作用:标记需要注入的属性或构造函数
// 使用位置:属性或构造函数

@HiltViewModel
// 作用:标记可注入的ViewModel
// 使用位置:ViewModel类
  1. 限定符注解:
@Qualifier
// 作用:区分同类型的不同实现
// 使用位置:自定义限定符注解

@Named("name")
// 作用:通过名称区分同类型实现
// 使用位置:提供方法和注入点

使用流程:

// 1. Application配置
@HiltAndroidApp
class MyApplication : Application()

// 2. 模块配置
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    @Provides
    @Singleton
    fun provideDatabase(): Database
}

// 3. 注入使用
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    @Inject
    lateinit var database: Database
}

组件化结构:

App
 ├── :app(主模块)
 │    └── @HiltAndroidApp
 ├── :base(基础模块)
 │    └── @Module + @InstallIn
 ├── :common(公共模块)
 │    └── @Module + @InstallIn
 └── :feature_xxx(功能模块)
      └── @AndroidEntryPoint

核心就是通过不同的注解来管理依赖注入的范围和生命周期!

Hilt的注解都必须使用吗?

1. 最简配置示例

// 1. 应用层(必需)
@HiltAndroidApp
class MyApplication : Application()

// 2. 模块层(必需)
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    @Provides
    fun provideRepository(): Repository {
        return RepositoryImpl()
    }
}

如果只用这两层,会遇到以下问题:

// 问题1:无法注入依赖
class LoginViewModel {
    // 无法获取Repository实例
    private val repository: Repository  // ❌ 编译错误
}

// 问题2:无法在Android组件中使用
class LoginActivity : AppCompatActivity() {
    // 无法注入ViewModel
    private val viewModel: LoginViewModel  // ❌ 编译错误
}

2. 完整配置示例

// 1. 应用层
@HiltAndroidApp
class MyApplication : Application()

// 2. 模块层
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    @Provides  // 必需,告诉Hilt如何创建实例
    @Singleton // 可选,控制作用域
    fun provideRepository(): Repository {
        return RepositoryImpl()
    }
}

// 3. 实现层
@HiltViewModel  // 必需,支持ViewModel注入
class LoginViewModel @Inject constructor(
    private val repository: Repository  // 通过构造注入获取依赖
) : ViewModel()

// 4. 使用层
@AndroidEntryPoint  // 必需,标记注入点
class LoginActivity : AppCompatActivity() {
    private val viewModel: LoginViewModel by viewModels()  // 正常工作 ✅
}

3. 各注解的必要性

// 1. @HiltAndroidApp - 必需
// 初始化Hilt,没有它其他注解都无法工作

// 2. @Module @InstallIn - 必需
// 告诉Hilt在哪里找到依赖的实现

// 3. @Provides @Singleton - 必需至少一个
// @Provides:告诉Hilt如何创建实例
// 或者使用 @Inject constructor() 构造注入

// 4. @HiltViewModel - 在使用ViewModel时必需
// 支持ViewModel的依赖注入

// 5. @AndroidEntryPoint - 在Android组件中使用时必需
// 标记可以接收依赖注入的Android组件

4. 最小配置示例

// 如果是简单的依赖注入,可以这样简化:

// 1. 应用层(必需)
@HiltAndroidApp
class MyApplication : Application()

// 2. 实现类(使用构造注入替代@Provides)
class Repository @Inject constructor() {
    // ...
}

// 3. 使用处(必需)
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    @Inject
    lateinit var repository: Repository
}

5. 为什么不能只用应用层和模块层

// 问题1:无法创建实例
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    // ❌ 缺少@Provides或@Inject,Hilt不知道如何创建实例
    fun provideRepository(): Repository
}

// 问题2:无法注入到Android组件
class MainActivity : AppCompatActivity() {
    // ❌ 缺少@AndroidEntryPoint,无法接收注入
    @Inject
    lateinit var repository: Repository
}

总结:

  1. @HiltAndroidApp - 必需,初始化Hilt
  2. @Module @InstallIn - 提供依赖时必需
  3. @Provides/@Inject - 必需至少一个,告诉Hilt如何创建实例
  4. @HiltViewModel - 使用ViewModel时必需
  5. @AndroidEntryPoint - 在Android组件中使用时必需

建议:

  • 不要过度简化,遵循Hilt的标准用法
  • 根据实际需求选择合适的注解组合
  • 保持依赖注入的清晰和可维护性

组件化在Gradle编译中的优势

graph TD
    A[非组件化编译] --> B[所有代码一起编译]
    B --> C[任何修改都需要全量编译]
    C --> D[较长的编译时间]

    E[组件化编译] --> F[独立模块并行编译]
    F --> G[增量编译]
    G --> H[显著减少编译时间]

主要优势:

1. 并行编译

// build.gradle
android {
    // 开启并行编译
    dexOptions {
        preDexLibraries = true
        maxProcessCount = 8  // 并行数
    }
}

// 各模块可以同时编译
:app
:module_login   ↘
:module_home     → 并行执行
:module_profile ↗

2. 增量编译

// 只编译修改的模块
修改login模块 → 只重新编译login模块
修改home模块 → 只重新编译home模块

// 非组件化
修改任何代码 → 需要重新编译整个项目

3. 编译缓存优化

// build.gradle
android {
    buildCache {
        enabled = true
    }
}

// 模块级缓存
:module_login:build  → module_login缓存
:module_home:build   → module_home缓存
:module_profile:build → module_profile缓存

4. 依赖隔离

// app/build.gradle
dependencies {
    if (isDebug) {
        implementation project(':module_login')
        implementation project(':module_home')
    } else {
        runtimeOnly project(':module_login')
        runtimeOnly project(':module_home')
    }
}

// 避免不必要的依赖编译

5. 资源隔离

// 每个模块独立的资源
module_login/
    src/main/res/
module_home/
    src/main/res/

// 避免资源冲突和重复编译

6. 构建变体优化

// 模块级别的构建变体
android {
    productFlavors {
        free {
            // 免费版本
        }
        paid {
            // 付费版本
        }
    }
}

// 可以只编译需要的模块和变体

7. 编译速度对比

非组件化项目:
修改一行代码 → 编译时间:3-5分钟

组件化项目:
修改一个模块 → 编译时间:30秒-1分钟

8. 内存使用优化

// gradle.properties
org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=512m

// 每个模块可以独立控制内存使用
// 避免整体项目的内存压力

9. CI/CD优势

# Jenkins pipeline
stages:
    - compile_login_module
    - compile_home_module
    - compile_profile_module
    
# 可以并行执行,加快构建速度

10. 调试优化

// 开发时可以只运行单个模块
./gradlew :module_login:assembleDebug

// 避免编译整个项目
// 加快开发调试速度

实际收益统计:

1. 编译时间
- 全量编译:减少40-60%
- 增量编译:减少70-90%

2. 内存使用
- 峰值减少:30-50%
- GC压力减少:40-60%

3. 开发效率
- 调试速度提升:50-80%
- 代码修改反馈更快

最佳实践建议:

1. 合理划分模块粒度
2. 做好模块间依赖管理
3. 使用buildSrc统一依赖
4. 配置proper gradle.properties
5. 使用并行编译
6. 启用构建缓存
7. 控制资源文件大小
8. 及时清理无用资源

这些优势使得组件化在大型项目中特别有价值,能显著提升开发效率和编译速度。

单独Module的配置运行

1. 首先在根目录的gradle.properties中添加配置开关

# gradle.properties
isRunAlone=true
debugModule=module_login  # 当前调试的模块名

2. 在每个Feature模块的build.gradle中配置

// module_login/build.gradle

def isRunAlone = rootProject.ext.isRunAlone
def debugModule = rootProject.ext.debugModule

if (isRunAlone && debugModule == "module_login") {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}

android {
    defaultConfig {
        if (isRunAlone && debugModule == "module_login") {
            applicationId "com.example.login"  // 独立运行时的包名
        }
    }
    
    sourceSets {
        main {
            if (isRunAlone && debugModule == "module_login") {
                // 独立运行时使用的清单文件
                manifest.srcFile 'src/main/alone/AndroidManifest.xml'
                // 独立运行时的资源文件
                java.srcDirs += "src/main/alone/java"
                res.srcDirs += "src/main/alone/res"
            } else {
                manifest.srcFile 'src/main/AndroidManifest.xml'
            }
        }
    }
}

3. 创建独立运行时的清单文件

<!-- module_login/src/main/alone/AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.login">
    
    <application
        android:name=".LoginApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        
        <activity android:name=".LoginActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

4. 创建独立运行时的Application

// module_login/src/main/alone/java/com/example/login/LoginApplication.kt
@HiltAndroidApp
class LoginApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        // 独立运行时的初始化
    }
}

5. 模块间通信的处理

// 使用接口隔离
interface LoginService {
    fun login(username: String, password: String)
}

// 在独立运行时提供mock实现
if (isRunAlone) {
    class MockLoginService : LoginService {
        override fun login(username: String, password: String) {
            // mock实现
        }
    }
}

6. 依赖配置

dependencies {
    // 基础依赖
    implementation project(':common')
    
    // 独立运行时的依赖
    if (isRunAlone && debugModule == "module_login") {
        implementation 'androidx.appcompat:appcompat:1.x.x'
        implementation 'com.google.android.material:material:1.x.x'
        // 其他需要的依赖
    }
}

7. 快速切换脚本

// 创建gradle task快速切换模块
task switchToLogin() {
    doLast {
        def propertiesFile = file('gradle.properties')
        def properties = new Properties()
        properties.load(propertiesFile.newDataInputStream())
        properties.setProperty('isRunAlone', 'true')
        properties.setProperty('debugModule', 'module_login')
        properties.store(propertiesFile.newWriter(), null)
    }
}

使用方法:

# 命令行切换到登录模块
./gradlew switchToLogin

# 只编译登录模块
./gradlew :module_login:assembleDebug

# 直接运行登录模块
./gradlew :module_login:installDebug

目录结构:

module_login/
├── build.gradle
├── src/
│   ├── main/
│   │   ├── java/
│   │   ├── res/
│   │   └── AndroidManifest.xml
│   └── alone/
│       ├── java/
│       ├── res/
│       └── AndroidManifest.xml

优势:

  1. 显著减少编译时间
  2. 加快开发调试速度
  3. 便于模块独立测试
  4. 支持并行开发
  5. 减少内存占用

注意事项:

  1. 合理管理依赖
  2. 处理好模块间通信
  3. 维护好独立运行的配置
  4. 注意资源命名冲突
  5. 保持清单文件的同步

这样配置后,可以实现快速切换和独立编译运行特定模块,大大提高开发效率。

Hilt配置完组件化后的编译过程

让我详细解释使用Hilt的组件化项目的编译流程:

graph TD
    A[项目编译开始] --> B[Hilt注解处理]
    B --> C{各Feature模块并行处理}
    
    C --> D[Login模块]
    C --> E[Home模块]
    C --> F[Profile模块]
    
    D --> G[生成Login_HiltComponents]
    E --> H[生成Home_HiltComponents]
    F --> I[生成Profile_HiltComponents]
    
    G --> J[合并依赖图]
    H --> J
    I --> J
    
    J --> K[生成最终Application_HiltComponents]
    K --> L[完成编译]

详细编译流程:

1. 初始化阶段

// 1. 检查Hilt配置
@HiltAndroidApp
class MyApplication : Application()

// 2. 收集所有模块的Hilt组件
modules/
  ├── app/
  │   └── @HiltAndroidApp
  ├── feature_login/
  │   └── @Module @InstallIn
  ├── feature_home/
  │   └── @Module @InstallIn
  └── feature_profile/
      └── @Module @InstallIn

2. 注解处理阶段

// 1. 处理@HiltAndroidApp
class Hilt_MyApplication : Application() {
    private var injected = false
    
    @Override
    fun onCreate() {
        // 初始化Hilt组件
        DaggerMyApplication_HiltComponents_SingletonC
            .builder()
            .build()
    }
}

// 2. 处理各模块的@Module
@Generated("dagger.hilt.processor.internal.root.RootProcessor")
class LoginModule_ProvideLoginRepositoryFactory {
    // 生成Factory类
}

3. 依赖图构建

// 1. 模块级依赖图
@Component(modules = [
    LoginModule::class,
    HomeModule::class,
    ProfileModule::class
])
interface AppComponent {
    // 组件依赖关系
}

// 2. 作用域管理
@Singleton
@Component.Builder
interface Builder {
    // 构建器定义
}

4. 代码生成阶段

// 1. 生成各模块的组件工厂
class DaggerLoginComponent {
    static Builder builder() {
        return new Builder();
    }
}

// 2. 生成最终的应用组件
class DaggerMyApplication_HiltComponents {
    // 整合所有模块的依赖
}

5. 并行编译优化

// build.gradle
android {
    // 开启并行编译
    dexOptions {
        preDexLibraries = true
        maxProcessCount = 8
    }
}

6. 增量编译支持

// 只重新编译修改的模块
@Module
@InstallIn(SingletonComponent::class)
object LoginModule {
    // 修改此模块只会触发相关代码重新编译
}

7. 编译时验证

// 1. 作用域验证
@ActivityScoped
class LoginViewModel @Inject constructor() // 编译时检查作用域

// 2. 依赖验证
class HomeViewModel @Inject constructor(
    private val repository: HomeRepository // 编译时检查依赖可用性
)

8. 组件合并过程

graph LR
    A[Login组件] --> D[合并]
    B[Home组件] --> D
    C[Profile组件] --> D
    D --> E[最终应用组件]

9. 编译产物

build/
  ├── generated/
  │   └── hilt/
  │       ├── components/
  │       ├── factories/
  │       └── proxies/
  └── intermediates/
      └── hilt/

关键优化点:

1. 并行处理

// 各模块可以并行处理
LoginModule_Proxy ─┐
HomeModule_Proxy  ─┼─> 最终合并
ProfileModule_Proxy┘

2. 增量编译

// 修改单个模块只重新生成相关代码
修改LoginModule ─> 只重新生成Login相关代码

3. 缓存优化

android {
    buildCache {
        enabled = true
    }
}

4. 内存优化

// gradle.properties
org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=512m

编译性能对比:

传统编译:
修改一个模块 -> 重新编译所有代码
编译时间:3-5分钟

Hilt组件化编译:
修改一个模块 -> 只重新编译变更模块
编译时间:30秒-1分钟

最佳实践:

1. 模块划分

app/
  ├── common/
  ├── feature_login/
  ├── feature_home/
  └── feature_profile/

2. 依赖管理

// 使用buildSrc统一管理依赖
object Deps {
    const val hiltAndroid = "com.google.dagger:hilt-android:2.x.x"
    const val hiltCompiler = "com.google.dagger:hilt-compiler:2.x.x"
}

3. 编译配置

// 优化编译配置
android {
    compileSdkVersion 33
    buildToolsVersion "33.0.0"
    
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }
}

这样的编译流程能够显著提升组件化项目的编译效率和开发体验。

Application_HiltComponents的详细讲解

Application_HiltComponents 是Hilt在编译时生成的一个最终的依赖图类,它包含了所有模块的依赖关系。让我详细解释:

1. 编译过程

// 1. 各模块的依赖定义
@Module
@InstallIn(SingletonComponent::class)
object LoginModule {
    @Provides
    fun provideLoginRepository(): LoginRepository
}

@Module
@InstallIn(SingletonComponent::class)
object HomeModule {
    @Provides
    fun provideHomeRepository(): HomeRepository
}

// 2. Hilt编译时会生成代理类
// build/generated/source/kapt/debug/
LoginModule_Proxy
HomeModule_Proxy
ProfileModule_Proxy

// 3. 最终生成总的依赖组件类
DaggerApplication_HiltComponents

2. 生成的组件结构

// 简化版的生成代码结构
public final class DaggerApplication_HiltComponents {
    
    // 单例组件
    public final class SingletonC {
        // 所有模块提供的依赖
        private final LoginRepository loginRepository;
        private final HomeRepository homeRepository;
        private final ProfileRepository profileRepository;
        
        // 构造函数,初始化所有依赖
        SingletonC() {
            this.loginRepository = new LoginRepositoryImpl();
            this.homeRepository = new HomeRepositoryImpl();
            this.profileRepository = new ProfileRepositoryImpl();
        }
        
        // 获取依赖的方法
        LoginRepository getLoginRepository() {
            return loginRepository;
        }
        
        HomeRepository getHomeRepository() {
            return homeRepository;
        }
    }
    
    // Activity组件
    public final class ActivityC {
        // 持有上层组件引用
        private final SingletonC singletonC;
        
        // Activity级别的依赖
        private final ActivityViewModel viewModel;
    }
    
    // 其他作用域的组件...
}

3. 依赖注入过程

// 1. 应用启动时
@HiltAndroidApp
class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        // Hilt自动调用生成的代码
        DaggerApplication_HiltComponents.builder()
            .build()
            .inject(this)
    }
}

// 2. 注入到Activity
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    @Inject
    lateinit var loginRepository: LoginRepository
    
    override fun onCreate(savedInstanceState: Bundle?) {
        // Hilt自动从组件中获取依赖
        super.onCreate(savedInstanceState)
    }
}

4. 组件层级关系

DaggerApplication_HiltComponents
    ├── SingletonComponent(应用级别)
    │   ├── LoginRepository
    │   ├── HomeRepository
    │   └── ProfileRepository
    │
    ├── ActivityRetainedComponent
    │   └── ViewModels
    │
    ├── ActivityComponent
    │   └── Activity级别依赖
    │
    └── FragmentComponent
        └── Fragment级别依赖
  1. 实际作用
// 1. 管理依赖的生命周期
@Singleton  // 应用级别单例
class LoginRepository @Inject constructor()

@ActivityScoped  // Activity级别单例
class Navigator @Inject constructor()

// 2. 处理依赖关系
class LoginViewModel @Inject constructor(
    private val repository: LoginRepository,  // 从SingletonComponent获取
    private val navigator: Navigator         // 从ActivityComponent获取
)

// 3. 确保依赖的正确性
// 编译时检查:
// - 依赖是否都能提供
// - 作用域是否正确
// - 循环依赖是否存在

总结:

  1. Application_HiltComponents 是:

    • 所有依赖的容器
    • 管理依赖的生命周期
    • 处理依赖注入关系
    • 确保依赖的正确性
  2. 它的作用:

    • 集中管理所有依赖
    • 自动处理依赖注入
    • 维护依赖的作用域
    • 提供类型安全的依赖获取
  3. 对开发者来说:

    • 不需要直接使用这个类
    • Hilt自动处理所有依赖注入
    • 只需要关注依赖的定义和使用

这就是为什么Hilt能够自动处理依赖注入,而我们只需要使用注解来定义依赖关系。

流程总结图

graph TD
    A[开始编译] --> B[扫描Hilt注解]
    
    B --> C1[LoginModule]
    B --> C2[HomeModule]
    B --> C3[ProfileModule]
    
    C1 --> D1[生成LoginModule_Proxy]
    C2 --> D2[生成HomeModule_Proxy]
    C3 --> D3[生成ProfileModule_Proxy]
    
    D1 --> E[合并所有Proxy]
    D2 --> E
    D3 --> E
    
    E --> F[生成DaggerApplication_HiltComponents]
    
    F --> G[SingletonComponent]
    F --> H[ActivityComponent]
    F --> I[FragmentComponent]
    
    G --> J[运行时依赖注入]

详细解释每个步骤:

graph TD
    A[1. 编译开始] --> B[2. 注解处理]
    B --> C[3. 生成代理类]
    C --> D[4. 合并依赖图]
    D --> E[5. 生成最终组件]
    E --> F[6. 运行时注入]
    
    subgraph "2. 注解处理"
        B1[HiltAndroidApp]
        B2[Module]
        B3[Provides]
        B4[Inject]
    end
    
    subgraph "3. 代理类生成"
        C1[LoginModule_Proxy]
        C2[HomeModule_Proxy]
        C3[ProfileModule_Proxy]
    end
    
    subgraph "4. 依赖图合并"
        D1[验证依赖关系]
        D2[检查作用域]
        D3[合并提供方法]
    end
    
    subgraph "5. 组件生成"
        E1[SingletonComponent]
        E2[ActivityComponent]
        E3[FragmentComponent]
    end
    
    subgraph "6. 运行时"
        F1[初始化组件]
        F2[注入依赖]
        F3[管理生命周期]
    end

使用流程:

graph LR
    A[定义依赖] --> B[编译处理]
    B --> C[生成代码]
    C --> D[运行注入]
    
    subgraph "定义依赖"
        A1[Module]
        A2[Provides]
        A3[Inject]
    end
    
    subgraph "编译处理"
        B1[注解处理器]
        B2[生成代理]
        B3[依赖验证]
    end
    
    subgraph "生成代码"
        C1[组件类]
        C2[工厂类]
        C3[注入器]
    end
    
    subgraph "运行注入"
        D1[初始化]
        D2[获取依赖]
        D3[生命周期]
    end

组件层级:

graph TD
    A[SingletonComponent] --> B[ActivityRetainedComponent]
    B --> C[ActivityComponent]
    C --> D[FragmentComponent]
    D --> E[ViewComponent]
    E --> F[ViewWithFragmentComponent]
    
    subgraph "作用域"
        A1[Singleton]
        C1[ActivityScoped]
        D1[FragmentScoped]
    end

这些流程图展示了:

  1. Hilt的编译过程
  2. 依赖处理流程
  3. 组件生成过程
  4. 运行时注入流程
  5. 组件层级关系

希望这些图能帮助你更好地理解Hilt的工作原理!

Navigation在组件化中的应用

结合Compose来详细说明Navigation在组件化项目中的应用:

1. 基础导航配置

// common/navigation/NavigationGraph.kt
sealed class NavigationGraph(val route: String) {
    object Login : NavigationGraph("login")
    object Home : NavigationGraph("home")
    data class Profile(val userId: String? = null) : 
        NavigationGraph("profile?userId={userId}") {
        fun createRoute(userId: String) = "profile?userId=$userId"
    }
}

// app/MainActivity.kt
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    @Inject lateinit var navigationService: NavigationService
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            AppNavigation()
        }
    }
}

自定义NavigationGraph

// 1. 直接使用字符串容易出错
navController.navigate("login")  // 可能拼写错误
navController.navigate("profile/123")  // 格式可能错误

// 2. 自定义后
sealed class NavigationGraph(val route: String) {
    object Login : NavigationGraph("login")
    data class Profile(val userId: String? = null) : 
        NavigationGraph("profile/{userId}")
}

// 使用时更安全
navController.navigate(NavigationGraph.Login.route)  // IDE自动完成
navController.navigate(NavigationGraph.Profile("123").route)  // 类型安全

2. 主导航图设置

// app/navigation/AppNavigation.kt
@Composable
fun AppNavigation() {
    val navController = rememberNavController()
    
    NavHost(
        navController = navController,
        startDestination = NavigationGraph.Login.route
    ) {
        // 登录模块导航
        loginNavigation(navController)
        // 首页模块导航
        homeNavigation(navController)
        // 个人中心模块导航
        profileNavigation(navController)
    }
}

3. Feature模块导航配置

// feature_login/navigation/LoginNavigation.kt
fun NavGraphBuilder.loginNavigation(
    navController: NavController
) {
    navigation(
        startDestination = "login_main",
        route = NavigationGraph.Login.route
    ) {
        composable("login_main") {
            LoginScreen(
                onNavigateToHome = {
                    navController.navigate(NavigationGraph.Home.route) {
                        popUpTo(NavigationGraph.Login.route) { inclusive = true }
                    }
                }
            )
        }
    }
}

// feature_login/ui/LoginScreen.kt
@Composable
fun LoginScreen(
    onNavigateToHome: () -> Unit,
    viewModel: LoginViewModel = hiltViewModel()
) {
    val uiState by viewModel.uiState.collectAsState()
    
    LoginContent(
        uiState = uiState,
        onLoginClick = { username, password ->
            viewModel.login(username, password)
        },
        onLoginSuccess = onNavigateToHome
    )
}
NavGraphBuilder的详解

NavGraphBuilder 是 Jetpack Navigation 组件提供的系统类,用于构建导航图。让我详细解释其使用方式:

  1. 扩展函数定义
// 1. 基本扩展函数结构
fun NavGraphBuilder.loginNavigation(
    navController: NavController
) {
    // 这是一个NavGraphBuilder的扩展函数
    // 用于模块化导航图的构建
}

// 2. 在主导航图中使用
@Composable
fun AppNavigation() {
    val navController = rememberNavController()
    
    NavHost(
        navController = navController,
        startDestination = NavigationGraph.Login.route
    ) {
        // 这里的it或this就是NavGraphBuilder
        loginNavigation(navController)
        homeNavigation(navController)
        profileNavigation(navController)
    }
}
  1. 完整的模块导航示例
// feature_login/navigation/LoginNavigation.kt

fun NavGraphBuilder.loginNavigation(
    navController: NavController
) {
    // 创建一个子导航图
    navigation(
        startDestination = "login_main",  // 子图的起始目的地
        route = NavigationGraph.Login.route  // 子图的路由
    ) {
        // 登录主页面
        composable("login_main") {
            LoginScreen(
                onNavigateToHome = {
                    navController.navigate(NavigationGraph.Home.route) {
                        // 导航选项
                        popUpTo(NavigationGraph.Login.route) { 
                            inclusive = true  // 包含当前路由
                        }
                    }
                }
            )
        }
        
        // 注册页面
        composable("login_register") {
            RegisterScreen()
        }
        
        // 忘记密码页面
        composable("login_forgot_password") {
            ForgotPasswordScreen()
        }
    }
}
  1. 常用的 NavGraphBuilder 函数
fun NavGraphBuilder.loginNavigation(
    navController: NavController
) {
    // 1. composable - 添加组合页面
    composable(
        route = "login",
        arguments = listOf(
            navArgument("userId") { type = NavType.StringType }
        ),
        deepLinks = listOf(
            navDeepLink { uriPattern = "example://login/{userId}" }
        )
    ) {
        LoginScreen()
    }
    
    // 2. navigation - 创建子导航图
    navigation(
        startDestination = "login_main",
        route = "login_graph"
    ) {
        // 子导航图内容
    }
    
    // 3. dialog - 添加对话框目的地
    dialog("login_dialog") {
        LoginDialog()
    }
}
  1. 带动画的导航
fun NavGraphBuilder.loginNavigation(
    navController: NavController
) {
    composable(
        route = "login",
        enterTransition = {
            slideIntoContainer(AnimatedContentScope.SlideDirection.Left)
        },
        exitTransition = {
            slideOutOfContainer(AnimatedContentScope.SlideDirection.Right)
        }
    ) {
        LoginScreen()
    }
}
  1. 参数传递
fun NavGraphBuilder.loginNavigation(
    navController: NavController
) {
    composable(
        route = "login?userId={userId}&type={type}",
        arguments = listOf(
            navArgument("userId") {
                type = NavType.StringType
                nullable = true
                defaultValue = null
            },
            navArgument("type") {
                type = NavType.StringType
                defaultValue = "normal"
            }
        )
    ) { backStackEntry ->
        // 获取参数
        val userId = backStackEntry.arguments?.getString("userId")
        val type = backStackEntry.arguments?.getString("type")
        
        LoginScreen(userId = userId, type = type)
    }
}
  1. 嵌套导航
fun NavGraphBuilder.loginNavigation(
    navController: NavController
) {
    navigation(
        startDestination = "login_main",
        route = "login_graph"
    ) {
        composable("login_main") {
            LoginScreen()
        }
        
        // 嵌套的认证流程
        navigation(
            startDestination = "auth_password",
            route = "auth_graph"
        ) {
            composable("auth_password") {
                PasswordScreen()
            }
            composable("auth_2fa") {
                TwoFactorAuthScreen()
            }
        }
    }
}

使用建议:

  1. 每个功能模块创建独立的导航扩展函数
  2. 使用 navigation 创建子导航图
  3. 合理组织页面层级
  4. 注意参数传递的类型安全
  5. 适当添加转场动画

这样的模块化导航结构可以让代码更清晰,更易维护,同时也支持功能模块的独立开发和测试。

4. 参数传递

// feature_profile/navigation/ProfileNavigation.kt
fun NavGraphBuilder.profileNavigation(
    navController: NavController
) {
    navigation(
        startDestination = "profile_main",
        route = NavigationGraph.Profile.route
    ) {
        composable(
            route = "profile_main?userId={userId}",
            arguments = listOf(
                navArgument("userId") {
                    type = NavType.StringType
                    nullable = true
                }
            )
        ) { backStackEntry ->
            val userId = backStackEntry.arguments?.getString("userId")
            ProfileScreen(userId = userId)
        }
    }
}

5. 统一导航服务

// common/navigation/NavigationService.kt
@Singleton
class NavigationServiceImpl @Inject constructor() {
    private lateinit var navController: NavController
    
    fun init(navController: NavController) {
        this.navController = navController
    }
    
    fun navigateToProfile(userId: String) {
        navController.navigate(
            NavigationGraph.Profile.createRoute(userId)
        )
    }
}

// 在Compose中使用
@Composable
fun SomeScreen(
    navigationService: NavigationService = hiltViewModel()
) {
    Button(onClick = { 
        navigationService.navigateToProfile("123") 
    }) {
        Text("Go to Profile")
    }
}

6. Deep Links支持

// feature_home/navigation/HomeNavigation.kt
fun NavGraphBuilder.homeNavigation(
    navController: NavController
) {
    navigation(
        startDestination = "home_main",
        route = NavigationGraph.Home.route
    ) {
        composable(
            route = "home_main",
            deepLinks = listOf(
                navDeepLink {
                    uriPattern = "example://home"
                }
            )
        ) {
            HomeScreen()
        }
    }
}

7. 动画过渡

// common/navigation/NavigationAnimation.kt
@Composable
fun NavigationAnimation(
    content: @Composable AnimatedVisibilityScope.() -> Unit
) {
    AnimatedVisibility(
        visible = true,
        enter = slideInHorizontally() + fadeIn(),
        exit = slideOutHorizontally() + fadeOut(),
        content = content
    )
}

// 在导航中使用
composable(
    route = "profile_main",
    enterTransition = {
        slideIntoContainer(AnimatedContentScope.SlideDirection.Left)
    },
    exitTransition = {
        slideOutOfContainer(AnimatedContentScope.SlideDirection.Right)
    }
) {
    NavigationAnimation {
        ProfileScreen()
    }
}

8. 状态保持

// feature_home/ui/HomeScreen.kt
@Composable
fun HomeScreen(
    viewModel: HomeViewModel = hiltViewModel()
) {
    // 使用rememberSaveable保持状态
    var selectedTab by rememberSaveable { mutableStateOf(0) }
    
    Column {
        TabRow(selectedTabIndex = selectedTab) {
            // Tabs
        }
        when (selectedTab) {
            0 -> Tab1Content()
            1 -> Tab2Content()
        }
    }
}

优势:

  1. 声明式导航

    • 更符合Compose的声明式UI理念
    • 代码更清晰易读
  2. 类型安全

    • 参数传递更安全
    • 路由定义集中管理
  3. 状态管理

    • 与Compose状态管理无缝集成
    • 支持状态保持和恢复
  4. 动画支持

    • 内置转场动画
    • 自定义动画更简单
  5. 测试友好

    • 可以方便地测试导航逻辑
    • 支持UI测试

使用建议:

  1. 统一管理导航路由
  2. 合理使用动画过渡
  3. 注意状态保持
  4. 处理好返回栈
  5. 做好深链接支持

这样的导航架构能让组件化的Compose项目更加清晰和易维护。

总结

Navigation在组件化中主要解决了这两个核心问题。

1. 模块间跳转

// 1. 在common模块定义导航路由
sealed class NavigationGraph(val route: String) {
    object Login : NavigationGraph("login")
    object Home : NavigationGraph("home")
    object Profile : NavigationGraph("profile")
}

// 2. 在各个功能模块中定义导航
fun NavGraphBuilder.loginNavigation(
    navController: NavController
) {
    navigation(
        startDestination = "login_main",
        route = NavigationGraph.Login.route
    ) {
        composable("login_main") {
            LoginScreen(
                onLoginSuccess = {
                    // 跳转到home模块
                    navController.navigate(NavigationGraph.Home.route)
                }
            )
        }
    }
}

2. 参数传递

// 1. 定义带参数的路由
sealed class NavigationGraph(val route: String) {
    // 必选参数
    object ProductDetail : NavigationGraph("product/{productId}") {
        fun createRoute(productId: String) = "product/$productId"
    }
    
    // 可选参数
    object Profile : NavigationGraph("profile?userId={userId}") {
        fun createRoute(userId: String?) = "profile?userId=$userId"
    }
}

// 2. 配置参数
fun NavGraphBuilder.productNavigation(
    navController: NavController
) {
    composable(
        route = NavigationGraph.ProductDetail.route,
        arguments = listOf(
            navArgument("productId") { 
                type = NavType.StringType 
            }
        )
    ) { backStackEntry ->
        // 获取参数
        val productId = backStackEntry.arguments?.getString("productId")
        ProductDetailScreen(productId = productId)
    }
}

3. 完整的跨模块通信示例

// 1. 定义导航事件
sealed class NavigationEvent {
    data class ToProductDetail(val productId: String) : NavigationEvent()
    data class ToUserProfile(val userId: String?) : NavigationEvent()
    object ToCart : NavigationEvent()
}

// 2. 导航管理器
@Singleton
class NavigationManager @Inject constructor() {
    private val _navigationEvent = MutableSharedFlow<NavigationEvent>()
    val navigationEvent = _navigationEvent.asSharedFlow()
    
    suspend fun navigate(event: NavigationEvent) {
        _navigationEvent.emit(event)
    }
}

// 3. 在ViewModel中使用
@HiltViewModel
class ProductViewModel @Inject constructor(
    private val navigationManager: NavigationManager
) : ViewModel() {
    fun onProductClick(productId: String) {
        viewModelScope.launch {
            navigationManager.navigate(
                NavigationEvent.ToProductDetail(productId)
            )
        }
    }
}

// 4. 在主Activity中处理导航
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    @Inject
    lateinit var navigationManager: NavigationManager
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val navController = rememberNavController()
            
            // 收集导航事件
            LaunchedEffect(Unit) {
                navigationManager.navigationEvent.collect { event ->
                    when (event) {
                        is NavigationEvent.ToProductDetail -> {
                            navController.navigate(
                                NavigationGraph.ProductDetail.createRoute(
                                    event.productId
                                )
                            )
                        }
                        is NavigationEvent.ToUserProfile -> {
                            navController.navigate(
                                NavigationGraph.Profile.createRoute(
                                    event.userId
                                )
                            )
                        }
                        NavigationEvent.ToCart -> {
                            navController.navigate(NavigationGraph.Cart.route)
                        }
                    }
                }
            }
            
            // 导航图
            NavHost(
                navController = navController,
                startDestination = NavigationGraph.Home.route
            ) {
                homeNavigation(navController)
                productNavigation(navController)
                profileNavigation(navController)
                cartNavigation(navController)
            }
        }
    }
}

4. 导航的优势

graph TD
    A[Navigation优势] --> B[类型安全]
    A --> C[参数传递]
    A --> D[生命周期管理]
    A --> E[深链接支持]
    
    B --> B1[编译时检查路由]
    B --> B2[参数类型检查]
    
    C --> C1[必选参数]
    C --> C2[可选参数]
    C --> C3[参数默认值]
    
    D --> D1[自动处理返回栈]
    D --> D2[状态保存恢复]
    
    E --> E1[支持外部跳转]
    E --> E2[支持应用内跳转]

5. 最佳实践

// 1. 路由统一管理
sealed class NavigationGraph(val route: String) {
    // 所有路由定义在一处
}

// 2. 参数封装
data class ProductDetailArgs(
    val productId: String,
    val from: String? = null
)

// 3. 导航扩展
fun NavController.navigateToProduct(args: ProductDetailArgs) {
    navigate(NavigationGraph.ProductDetail.createRoute(args))
}

// 4. 动画支持
fun NavGraphBuilder.productAnimation(
    content: @Composable () -> Unit
) {
    composable(
        route = NavigationGraph.ProductDetail.route,
        enterTransition = { slideInHorizontally() },
        exitTransition = { slideOutHorizontally() }
    ) {
        content()
    }
}

总结:

  1. Navigation解决了:

    • 模块间跳转
    • 参数传递
    • 类型安全
    • 生命周期管理
  2. 使用建议:

    • 统一管理路由
    • 封装导航逻辑
    • 规范参数传递
    • 合理使用动画

这样可以让组件化项目的导航更加清晰和可维护。