آموزش Dagger Hilt در اندروید– راهنمای گام به گام
اگر مدتی با توسعه اندروید کار کرده باشید، احتمالا با مشکل مدیریت وابستگیها (Dependencies) در پروژه روبهرو شدهاید. هرچه پروژه بزرگتر میشود، ساختن دستی آبجکتها و انتقال آنها بین کلاسها سختتر خواهد شد. اینجاست که Dependency Injection وارد میشود.
در این مقاله بهصورت کامل با Dagger Hilt آشنا میشویم؛ کتابخانهای مدرن از گوگل که استفاده از Dagger را در پروژههای اندرویدی بسیار سادهتر کرده است.
Dagger Hilt چیست؟
Dagger Hilt یک کتابخانه Dependency Injection برای اندروید است که روی Dagger ساخته شده و فرآیند تزریق وابستگیها را ساده میکند.
به کمک Hilt میتوانید:
- مدیریت وابستگیها را آسان کنید
- کدهای تمیزتر و قابل تستتری بنویسید
- از ساخت دستی آبجکتها جلوگیری کنید
- وابستگیها را در کل پروژه مدیریت کنید

Dependency Injection چیست؟
فرض کنید یک کلاس Repository داریم:
class UserRepository {
fun getUsers(): List<String> {
return listOf("Ali", "Sara")
}
}
و یک ViewModel:
class UserViewModel {
private val repository = UserRepository()
}
مشکل اینجاست که ViewModel خودش Repository را میسازد.
این کار مشکلاتی دارد:
- تستنویسی سخت میشود
- وابستگیها زیاد میشوند
- تغییر پیادهسازی دشوار میشود
در Dependency Injection وابستگی از بیرون وارد کلاس میشود:
class UserViewModel(
private val repository: UserRepository
)
چرا Hilt بهتر از Dagger خام است؟
استفاده مستقیم از Dagger معمولا پیچیده است و نیاز به:
- Component
- Factory
- Builder
- Moduleهای زیاد
دارد.
اما Hilt بسیاری از این موارد را خودکار انجام میدهد.
مزایای Hilt:
- راهاندازی ساده
- ادغام کامل با Android Jetpack
- مناسب برای MVVM
- پشتیبانی عالی از ViewModel
- مدیریت Scopeها
- کاهش Boilerplate
افزودن Hilt به پروژه
1. اضافه کردن Plugin
در فایل پروژه:
plugins {
id 'com.google.dagger.hilt.android' version '2.57.1' apply false
}
2. اضافه کردن Dependencyها
در فایل app:
plugins {
id 'kotlin-kapt'
id 'com.google.dagger.hilt.android'
}
dependencies {
implementation("com.google.dagger:hilt-android:2.57.1")
kapt("com.google.dagger:hilt-compiler:2.57.1")
}
3. فعال کردن kapt
kapt {
correctErrorTypes = true
}
ساخت Application Class
یک کلاس Application ایجاد کنید:
@HiltAndroidApp
class MyApp : Application()
و در AndroidManifest ثبت کنید:
<application
android:name=".MyApp"
اولین Dependency Injection
ساخت Repository
class UserRepository @Inject constructor() {
fun getName(): String {
return "Amooznegar"
}
}
استفاده در ViewModel
@HiltViewModel
class MainViewModel @Inject constructor(
private val repository: UserRepository
) : ViewModel() {
fun getData(): String {
return repository.getName()
}
}
استفاده در Activity
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
}
@Inject چیست؟
زمانی که روی Constructor قرار میگیرد، Hilt میفهمد چگونه آن کلاس را بسازد.
class MyRepository @Inject constructor()
یعنی:
هرجا MyRepository نیاز بود، خودت آن را بساز.
Module در Hilt چیست؟
گاهی کلاسهایی داریم که Constructor آنها دست ما نیست؛ مثلا:
- Retrofit
- Room
- SharedPreferences
در این شرایط از Module استفاده میکنیم.
ساخت Module
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
fun provideBaseUrl(): String {
return "https://api.test.com/"
}
}
@Provides چیست؟
به Hilt میگوید چگونه یک وابستگی را بسازد.
ساخت Retrofit با Hilt
Dependencyها
implementation("com.squareup.retrofit2:retrofit:2.11.0")
implementation("com.squareup.retrofit2:converter-gson:2.11.0")
ساخت Module
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
@Singleton
fun provideRetrofit(): Retrofit {
return Retrofit.Builder()
.baseUrl("https://api.test.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
}
}
استفاده از Retrofit
class ApiRepository @Inject constructor(
private val retrofit: Retrofit
)
Scope در Hilt
Scope مشخص میکند یک وابستگی چه مدت در حافظه بماند.
مهمترین Scopeها
| Scope | توضیح |
|---|---|
| Singleton | یک نمونه در کل برنامه |
| ActivityScoped | مخصوص Activity |
| ViewModelScoped | مخصوص ViewModel |
| FragmentScoped | مخصوص Fragment |
مثال Singleton
@Singleton
@Provides
fun provideRetrofit(): Retrofit
ViewModel Injection
یکی از بهترین ویژگیهای Hilt پشتیبانی مستقیم از ViewModel است.
@HiltViewModel
class HomeViewModel @Inject constructor(
private val repository: HomeRepository
) : ViewModel()
تزریق در Fragment
@AndroidEntryPoint
class HomeFragment : Fragment()
تزریق در Adapter
معمولا توصیه میشود Adapterها وابستگی زیادی نداشته باشند، اما در صورت نیاز:
class UserAdapter @Inject constructor() :
RecyclerView.Adapter<UserAdapter.ViewHolder>()
Qualifier در Hilt
گاهی دو نمونه از یک نوع داریم.
مثلا:
String
برای تشخیص از Qualifier استفاده میکنیم.
مثال Qualifier
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class BaseUrl
استفاده
@Provides
@BaseUrl
fun provideUrl(): String {
return "https://api.test.com/"
}
و:
class ApiService @Inject constructor(
@BaseUrl private val url: String
)
تزریق Interface
Interface
interface UserRepository {
fun getName(): String
}
پیادهسازی
class UserRepositoryImpl @Inject constructor() :
UserRepository {
override fun getName(): String {
return "Amooznegar"
}
}
Bind کردن
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
@Binds
abstract fun bindRepository(
impl: UserRepositoryImpl
): UserRepository
}
تفاوت @Provides و @Binds
| @Provides | @Binds |
|---|---|
| برای ساخت دستی آبجکت | برای Interfaceها |
| داخل object module | داخل abstract module |
| انعطاف بیشتر | سبکتر و سریعتر |
تزریق در Compose
اگر از Jetpack Compose استفاده میکنید:
@AndroidEntryPoint
class MainActivity : ComponentActivity()
و:
val viewModel: MainViewModel = hiltViewModel()
Hilt و Room
Dependency
implementation("androidx.room:room-runtime:2.7.2")
kapt("androidx.room:room-compiler:2.7.2")
ساخت Database
@Database(
entities = [UserEntity::class],
version = 1
)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
Module
@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {
@Provides
@Singleton
fun provideDatabase(
@ApplicationContext context: Context
): AppDatabase {
return Room.databaseBuilder(
context,
AppDatabase::class.java,
"app.db"
).build()
}
}
Hilt Testing
یکی از مزایای مهم Hilt تستپذیری بالا است.
برای تست میتوانید Fake Repository تزریق کنید.
خطاهای رایج Hilt
فراموش کردن @AndroidEntryPoint
یکی از رایجترین خطاها:
Hilt Activity must be attached to an @AndroidEntryPoint
فراموش کردن @Inject constructor
اگر Constructor را Inject نکنید:
No binding found
Circular Dependency
زمانی که دو کلاس به هم وابسته باشند.
مثلا:
A -> B -> A
معماری پیشنهادی با Hilt
ترکیب بسیار محبوب:
- MVVM
- Repository Pattern
- Retrofit
- Room
- Coroutines
- Hilt
بهترین روشهای استفاده از Hilt
1. Repositoryها را Inject کنید
نه Activityها را.
2. از Singleton بیرویه استفاده نکنید
هر چیزی Singleton نیست.
3. Moduleها را تفکیک کنید
مثلا:
- NetworkModule
- DatabaseModule
- RepositoryModule
4. Interface محور توسعه دهید
برای تست بهتر.
آیا Hilt برای پروژههای کوچک مناسب است؟
بله.
حتی پروژههای کوچک هم با Dependency Injection تمیزتر میشوند.
اما قدرت واقعی Hilt در پروژههای متوسط و بزرگ مشخص میشود.
مقایسه Hilt و Koin
| Hilt | Koin |
|---|---|
| رسمی گوگل | Third Party |
| مبتنی بر Compile Time | Runtime |
| سریعتر | سادهتر |
| Boilerplate کمتر نسبت به Dagger | یادگیری آسانتر |
جمعبندی
Dagger Hilt یکی از مهمترین ابزارهای توسعه مدرن اندروید است که فرآیند Dependency Injection را بسیار ساده میکند.
اگر در حال توسعه پروژههای حرفهای اندروید هستید، یادگیری Hilt تقریبا ضروری است.
در این مقاله یاد گرفتیم:
- Dependency Injection چیست
- Hilt چگونه کار میکند
- نحوه راهاندازی Hilt
- ساخت Module
- استفاده از Retrofit و Room
- Scopeها
- Qualifier
- Interface Injection
- تست و خطاهای رایج
اگر به معماری تمیز، تستپذیری بالا و مدیریت بهتر پروژه اهمیت میدهید، Hilt انتخاب بسیار مناسبی است.