← Назад к вопросам

В чем разница между горячими и холодными потоками?

2.0 Middle🔥 161 комментариев
#Архитектура и паттерны#Многопоточность и асинхронность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое @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 separationScreen/Feature dependencies

Сценарии использования

Когда использовать Subcomponent:

  1. Зависимости, специфичные для экрана (Activity/Fragment)
  2. Иерархия компонентов (AppComponent → ScreenComponent → FeatureComponent)
  3. Разделение видимости зависимостей

Когда использовать @Component:

  1. Полностью независимые компоненты
  2. Разные слои приложения (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

  1. Используй для экранов/фичей — отдельный Subcomponent для каждого экрана
  2. Наследуй зависимости — Subcomponent автоматически видит родительские зависимости
  3. Используй scopes правильно — разные области видимости для разных уровней
  4. Builder для параметров — используй Builder для передачи параметров

Ответ: @Subcomponent создаёт вложенный компонент, который наследует зависимости от родительского компонента и имеет свою область видимости. Это полезно для структурирования иерархии зависимостей в больших приложениях.

В чем разница между горячими и холодными потоками? | PrepBro