برنامه‌نویسی اندروید

آموزش Dagger Hilt در اندروید– راهنمای گام به گام

آموزش Dagger Hilt در اندروید

اگر مدتی با توسعه اندروید کار کرده باشید، احتمالا با مشکل مدیریت وابستگی‌ها (Dependencies) در پروژه روبه‌رو شده‌اید. هرچه پروژه بزرگ‌تر می‌شود، ساختن دستی آبجکت‌ها و انتقال آن‌ها بین کلاس‌ها سخت‌تر خواهد شد. اینجاست که Dependency Injection وارد می‌شود.

در این مقاله به‌صورت کامل با Dagger Hilt آشنا می‌شویم؛ کتابخانه‌ای مدرن از گوگل که استفاده از Dagger را در پروژه‌های اندرویدی بسیار ساده‌تر کرده است.

Dagger Hilt چیست؟

Dagger Hilt یک کتابخانه Dependency Injection برای اندروید است که روی Dagger ساخته شده و فرآیند تزریق وابستگی‌ها را ساده می‌کند.

به کمک Hilt می‌توانید:

  • مدیریت وابستگی‌ها را آسان کنید
  • کدهای تمیزتر و قابل تست‌تری بنویسید
  • از ساخت دستی آبجکت‌ها جلوگیری کنید
  • وابستگی‌ها را در کل پروژه مدیریت کنید

آموزش 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 انتخاب بسیار مناسبی است.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *