How Dependency Injection Is Configured with Hilt Across the GSYGitHubApp Compose Modules
The GSYGitHubApp uses @HiltAndroidApp in the Application class to bootstrap a compile-time validated dependency graph, with core singletons provided via SingletonComponent-scoped modules and feature ViewModels receiving dependencies through constructor injection annotated with @HiltViewModel.
The gsygithubappcompose repository demonstrates a production-grade Android architecture where dependency injection configured with Hilt unifies the multi-module codebase. By leveraging Dagger’s compile-time code generation, the app ensures thread-safe singletons for networking and persistence while allowing feature modules to consume dependencies without manual factory boilerplate.
Application-Level Bootstrapping with @HiltAndroidApp
Hilt requires a single annotated Application class to trigger its code generation across all modules. In app/src/main/java/com/shuyu/gsygithubappcompose/GSYApplication.kt, the @HiltAndroidApp annotation generates the base component that wires together all modules and makes the Application context injectable:
package com.shuyu.gsygithubappcompose
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class GSYApplication : Application()
This annotation creates the SingletonComponent that lives for the duration of the application process and serves as the root for all dependency provision.
Core Singleton Modules in SingletonComponent
All foundational dependencies are installed in SingletonComponent, guaranteeing a single instance for the entire process regardless of which module requests them.
NetworkModule – Providing Retrofit and OkHttp
Located at core/network/src/main/java/com/shuyu/gsygithubappcompose/core/network/di/NetworkModule.kt, this module constructs the HTTP stack:
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
@Singleton
fun provideOkHttpClient(tokenInterceptor: TokenInterceptor): OkHttpClient {
// Configuration logic
}
@Provides
@Singleton
fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
// Builder configuration
}
@Provides
@Singleton
fun provideGitHubApiService(retrofit: Retrofit): GitHubApiService {
retrofit.create(GitHubApiService::class.java)
}
}
The TokenInterceptor itself is injected into the provider method, demonstrating how modules can depend on other bindings within the same component.
DatabaseModule – Room Database and DAOs
The core/database/src/main/java/com/shuyu/gsygithubappcompose/core/database/di/DatabaseModule.kt file provides the Room database and all Data Access Objects as singletons:
@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {
@Provides
@Singleton
fun provideAppDatabase(@ApplicationContext context: Context): AppDatabase {
return Room.databaseBuilder(
context,
AppDatabase::class.java,
"gsy_github_db"
)
.fallbackToDestructiveMigration(true)
.build()
}
@Provides
@Singleton
fun provideUserDao(db: AppDatabase) = db.userDao()
@Provides
@Singleton
fun provideRepositoryDao(db: AppDatabase) = db.repositoryDao()
}
All DAOs share the same AppDatabase instance, ensuring thread-safe database access throughout the app lifecycle.
DataStoreModule – Binding Interfaces to Implementations
Located in core/common/src/main/java/com/shuyu/gsygithubappcompose/core/common/di/DataStoreModule.kt, this module demonstrates the mixed use of @Binds for interfaces and @Provides for concrete classes:
@Module
@InstallIn(SingletonComponent::class)
abstract class DataStoreModule {
@Binds
abstract fun bindUserPreferencesDataStore(
impl: UserPreferencesDataStore
): IUserPreferencesDataStore
companion object {
@Provides
@Singleton
fun provideLanguageDataStore(
@ApplicationContext ctx: Context
) = LanguageDataStore(ctx)
}
}
The @Binds annotation efficiently links the interface to its implementation without boilerplate instantiation code, while the companion object handles concrete class provision.
CommonModule – Utility Bindings
The core/common/src/main/java/com/shuyu/gsygithubappcompose/core/common/di/CommonModule.kt binds utility interfaces like StringResourceProvider:
@Module
@InstallIn(SingletonComponent::class)
abstract class CommonModule {
@Binds
@Singleton
abstract fun bindStringResourceProvider(
impl: StringResourceProviderImpl
): StringResourceProvider
}
Feature-Level Dependency Injection with @HiltViewModel
Every feature module leverages @HiltViewModel to receive repositories and services automatically. In feature/welcome/src/main/java/com/shuyu/gsygithubappcompose/feature/welcome/WelcomeViewModel.kt:
@HiltViewModel
class WelcomeViewModel @Inject constructor(
private val userRepository: UserRepository
) : ViewModel() {
// ViewModel logic utilizing injected repository
}
The @Inject annotation on the constructor instructs Hilt to resolve the UserRepository parameter from the graph. This pattern repeats across the codebase:
- TrendingViewModel – Injects
TrendingRepository - LoginViewModel – Injects
UserRepositoryandNotificationRepository - RepoDetailInfoViewModel – Injects
RepositoryRepositoryandEventRepository
Wiring Injection Points in the UI Layer
Activities and Fragments use @AndroidEntryPoint to enable injection. For example, fragments obtain ViewModels using the by viewModels() delegate:
@AndroidEntryPoint
class WelcomeFragment : Fragment(R.layout.fragment_welcome) {
private val viewModel: WelcomeViewModel by viewModels()
}
For direct field injection in Activities (less common for ViewModels but supported):
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject
lateinit var userRepository: UserRepository
}
Summary
- Bootstrap:
GSYApplicationannotated with@HiltAndroidAppinitializes the global DI graph. - Core Modules:
NetworkModule,DatabaseModule,DataStoreModule, andCommonModuleinstall singletons intoSingletonComponentfor application-scoped instances. - Pattern: The project uses
@Bindsfor interface implementations and@Providesfor concrete class construction. - Feature Layer:
@HiltViewModelwith constructor injection eliminates manual ViewModel factory creation. - Compile-Time Safety: All dependencies are resolved at compile time, preventing runtime null pointer exceptions in the dependency graph.
Frequently Asked Questions
What is the entry point for Hilt in this Android app?
The entry point is the GSYApplication class in app/src/main/java/com/shuyu/gsygithubappcompose/GSYApplication.kt, annotated with @HiltAndroidApp. This annotation triggers Hilt's code generation and creates the SingletonComponent that manages all application-scoped dependencies.
How does Hilt provide singleton instances across different modules?
By annotating provider methods with @Singleton and installing modules in SingletonComponent::class, Hilt ensures only one instance exists per application lifecycle. For example, the OkHttpClient, AppDatabase, and various DAOs are all scoped to SingletonComponent, making them available as singletons throughout the multi-module architecture.
Why does the project use both @Binds and @Provides in DataStoreModule?
@Binds is used for interface-to-implementation mapping (like IUserPreferencesDataStore to UserPreferencesDataStore) because it generates more efficient code and requires less boilerplate than @Provides. However, @Provides is necessary for concrete classes like LanguageDataStore that require constructor parameters or manual instantiation logic. The module uses a companion object to contain @Provides methods within an abstract class that contains @Binds methods.
How do ViewModels obtain their dependencies in the feature modules?
Feature ViewModels use the @HiltViewModel annotation combined with constructor injection (@Inject). When a Fragment or Activity requests the ViewModel via by viewModels(), Hilt automatically supplies the required repository dependencies (such as UserRepository or TrendingRepository) that are defined in the core modules and scoped to SingletonComponent.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →