Clarification on HILT Scoping in Dependency Injection: Networking and ViewModel Components

35 Views Asked by At

I've been exploring HILT documentation and came across the information that scoping a binding incurs costs in both generated code size and runtime performance. The general guideline is to scope a binding only if it's necessary for the correctness of the code.

I'm seeking clarification on when it is appropriate to scope dependencies. To illustrate, I have two examples:

Example 1: Networking Retrofit Dependencies

I have my networking Retrofit dependencies installed in SingletonComponent. Should I consider scoping them, and if so, what factors should I take into account?

@InstallIn(SingletonComponent::class)
@Module
object RetrofitModule {
    private const val BASE_URL = "xyz"

    @Provides
    fun provideLoggingInterceptor(): HttpLoggingInterceptor = HttpLoggingInterceptor().apply {
        level = HttpLoggingInterceptor.Level.BODY
    }

    @Provides
    fun provideOkHttpClient(loggingInterceptor: HttpLoggingInterceptor): OkHttpClient =
        OkHttpClient.Builder()
            .addInterceptor(interceptor = loggingInterceptor)
            .build()

    @Provides
    fun provideRetrofitInstance(okHttpClient: OkHttpClient): Retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .client(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
}

Example 2: Mappers and Repository Dependencies in ViewModelComponent

For mappers and repository dependencies installed in ViewModelComponent, should scoping be applied? What considerations are important in this context?

@InstallIn(ViewModelComponent::class)
@Module
abstract class DataModule {
    companion object {

        @Provides
        fun provideCountMapper(): CountMapper = CountMapper()

        @Provides
        fun provideCountListMapper(countMapper: CountMapper): CountListMapper =
            CountListMapper(countMapper = countMapper) 
        
        @Provides
        fun providesCoroutineDispatcher(): CoroutineDispatcher = Dispatchers.IO
     }

   

    @Binds
    abstract fun bindXYZRepository(xyzRepositoryImpl: XYZRepositoryImpl): XYZRepository
}

Additionally, is it accurate to state that scoping a stateless object generally doesn't provide significant benefits and may introduce inefficiencies? Conversely, scoping a stateful object ensures consistent behavior and data management within its lifecycle.

0

There are 0 best solutions below