В чем разница между горячими и холодными потоками?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое @Subcomponent в Dagger?
@Subcomponent — это аннотация в Dagger 2 для создания иерархии компонентов. Subcomponent позволяет создавать вложенные компоненты, которые наследуют зависимости от родительского компонента (Parent Component). Это полезно для структурирования больших приложений и разделения области видимости зависимостей.
Основной концепт
Subcomponent имеет доступ ко всем зависимостям родительского компонента, но имеет свою собственную область видимости и собственные провайдеры.
// Parent Component
@Component(modules = [AppModule::class])
interface AppComponent {
fun userSubcomponent(): UserSubcomponent.Builder
}
// Subcomponent
@Subcomponent(modules = [UserModule::class])
interface UserSubcomponent {
fun inject(fragment: UserFragment)
@Subcomponent.Builder
interface Builder {
fun build(): UserSubcomponent
}
}
// Модули
@Module
class AppModule {
@Provides
fun provideContext(app: Application): Context = app
}
@Module
class UserModule {
@Provides
fun provideUserRepository(context: Context): UserRepository {
return UserRepository(context) // Доступ к context от AppModule
}
}
Использование Subcomponent
class UserActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Получаем AppComponent
val appComponent = (application as MyApp).appComponent
// Создаём UserSubcomponent
val userSubcomponent = appComponent.userSubcomponent().build()
userSubcomponent.inject(this)
}
}
@Subcomponent.Builder
Builder позволяет передать параметры при создании Subcomponent:
@Subcomponent(modules = [UserModule::class])
interface UserSubcomponent {
fun inject(fragment: UserFragment)
@Subcomponent.Builder
interface Builder {
fun userId(userId: String): Builder
fun build(): UserSubcomponent
}
}
@Module
class UserModule {
@Provides
fun provideUserId(id: String): String = id
}
// Использование
val userSubcomponent = appComponent
.userSubcomponent()
.userId("123")
.build()
Subcomponent vs @Component
| Аспект | @Component | @Subcomponent |
|---|---|---|
| Иерархия | Независимый | Вложенный (имеет родителя) |
| Доступ к родительским зависимостям | Нет | Да |
| Область видимости | Независимая | Наследует родительскую |
| Создание | напрямую | через родительский компонент |
| Использование | Feature separation | Screen/Feature dependencies |
Сценарии использования
Когда использовать Subcomponent:
- Зависимости, специфичные для экрана (Activity/Fragment)
- Иерархия компонентов (AppComponent → ScreenComponent → FeatureComponent)
- Разделение видимости зависимостей
Когда использовать @Component:
- Полностью независимые компоненты
- Разные слои приложения (Data, Domain, Presentation)
Практический пример: Feature с Subcomponent
// App Level
@Component(modules = [AppModule::class, RepositoryModule::class])
interface AppComponent {
fun userProfileSubcomponent(): UserProfileSubcomponent.Builder
}
// Feature Level (Subcomponent)
@Subcomponent(modules = [UserProfileModule::class])
interface UserProfileSubcomponent {
fun inject(fragment: UserProfileFragment)
@Subcomponent.Builder
interface Builder {
fun build(): UserProfileSubcomponent
}
}
// Модули
@Module
class UserProfileModule {
@Provides
fun provideUserProfileViewModel(
userRepository: UserRepository // из AppModule
): UserProfileViewModel {
return UserProfileViewModel(userRepository)
}
}
// Fragment
class UserProfileFragment : Fragment() {
@Inject
lateinit var viewModel: UserProfileViewModel
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val appComponent = (activity?.application as MyApp).appComponent
appComponent.userProfileSubcomponent().build().inject(this)
}
}
Области видимости (Scopes) с Subcomponent
@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class AppScope
@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class ScreenScope
@Component(modules = [AppModule::class])
@AppScope
interface AppComponent {
fun screenSubcomponent(): ScreenSubcomponent.Builder
}
@Subcomponent(modules = [ScreenModule::class])
@ScreenScope // Зависимости живут столько же сколько этот Subcomponent
interface ScreenSubcomponent {
fun inject(activity: MainActivity)
}
@Module
class ScreenModule {
@Provides
@ScreenScope
fun provideScreenData(): ScreenData = ScreenData() // Singleton на ScreenScope
}
Современный подход: Hilt
На современном Android используется Hilt вместо Dagger, который упрощает работу с Subcomponent:
@HiltAndroidApp
class MyApp : Application()
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject
lateinit var viewModel: MainViewModel
}
Hilt автоматически управляет иерархией компонентов через @HiltAndroidApp и @AndroidEntryPoint.
Правила использования Subcomponent
- Используй для экранов/фичей — отдельный Subcomponent для каждого экрана
- Наследуй зависимости — Subcomponent автоматически видит родительские зависимости
- Используй scopes правильно — разные области видимости для разных уровней
- Builder для параметров — используй Builder для передачи параметров
Ответ: @Subcomponent создаёт вложенный компонент, который наследует зависимости от родительского компонента и имеет свою область видимости. Это полезно для структурирования иерархии зависимостей в больших приложениях.