Dagger / Hilt: คืออะไร DI และการใช้งาน

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-05-03 เวลาอ่าน: 9 นาที

Dagger คือเฟรมเวิร์กการฉีดพึ่งพาสำหรับ Java และ Kotlin ที่สร้างโค้ด DI ในเวลาคอมไพล์ผ่านการประมวลผลคำอธิบายประกอบ Hilt คือชั้นครอบบน Dagger สำหรับ Android ที่ทำให้การตั้งค่าคอมโพเนนต์และการจัดการวงจรชีวิตง่ายขึ้น ตามข้อมูลจาก Google, 2025 มีการใช้ Hilt ในมากกว่า 70% ของแอป Android จาก Google Play Top-100 โดยรองรับ Activity, Fragment, ViewModel และ Service ผ่านคอมโพเนนต์ที่กำหนดไว้ล่วงหน้า เฟรมเวิร์กทั้งสองให้การตรวจสอบกราฟพึ่งพาในเวลาคอมไพล์ ซึ่งกำจัดข้อผิดพลาดการฉีดในรันไทม์

ประเด็นสำคัญ

  • Dagger — เฟรมเวิร์ก DI แบบคอมไพล์ไทม์พร้อมการสร้างโค้ดผ่านคำอธิบายประกอบ @Module, @Provides, @Component
  • Hilt — ชั้นครอบ Android ที่ทำให้ Dagger ง่ายขึ้นผ่าน @HiltAndroidApp, @AndroidEntryPoint, @HiltViewModel
  • Component — กราฟพึ่งพาที่เชื่อมต่อ Module กับเป้าหมาย Inject ผ่านเมธอดพร็อกซี
  • Scope — @Singleton, @ViewModelScoped, @ActivityScoped จัดการอายุการใช้งานของออบเจ็กต์ที่ถูกฉีด
  • Hilt รองรับโปรเจกต์หลายโมดูลผ่าน @InstallIn สำหรับกราฟพึ่งพาที่แยกกัน

Dagger / Hilt คืออะไร?

Dagger คือเฟรมเวิร์กการฉีดพึ่งพาที่มีการสร้างโค้ดในเวลาคอมไพล์ พัฒนาครั้งแรกที่ Square และส่งต่อให้ Google ในภายหลัง Dagger ใช้โปรเซสเซอร์คำอธิบายประกอบ Java APT เพื่อวิเคราะห์กราฟพึ่งพาและสร้างคลาสโรงงาน แตกต่างจาก DI ในรันไทม์ (Guice, Koin) ตรงที่ Dagger ไม่ใช้รีเฟลกชัน — โค้ดทั้งหมดถูกสร้างขึ้นในเวลาคอมไพล์ ซึ่งรับประกันประสิทธิภาพสูงสุดในรันไทม์และการตรวจจับข้อผิดพลาดในเวลาบิวด์

Hilt คือไลบรารีของ Google ที่สร้างบน Dagger และปรับให้เหมาะสมสำหรับ Android Hilt มีคอมโพเนนต์ที่กำหนดไว้ล่วงหน้าซึ่งสอดคล้องกับวงจรชีวิตของคอมโพเนนต์ Android: @SingletonComponent สำหรับ Application, @ActivityComponent สำหรับ Activity, @FragmentComponent สำหรับ Fragment, @ViewModelComponent สำหรับ Viewmoel ซึ่งช่วยลดการกำหนดค่า Component และ Module ตามปกติที่จำเป็นใน Dagger บริสุทธิ์ Hilt ยังสร้างกราฟพึ่งพาสำหรับแต่ละคอมโพเนนต์ Android โดยอัตโนมัติผ่าน @AndroidEntryPoint

ตามข้อมูลจาก Google I/O 2024 Hilt คือโซลูชันที่แนะนำสำหรับ DI ในแอปพลิเคชัน Android ที่เขียนด้วย Kotlin ไลบรารี Jetpack (Navigation, Room, WorkManager) มีการรวมเข้ากับ Hilt ในตัวผ่าน @HiltViewModel และ @HiltWorker ในโปรเจกต์ที่ไม่ได้ใช้ Android (ไลบรารี Java/Kotlin บริสุทธิ์, แอปพลิเคชันเซิร์ฟเวอร์) จะใช้ Dagger บริสุทธิ์โดยไม่มีชั้นครอบ Hilt

ปัญหาของการฉีดพึ่งพาด้วยตนเอง

หากไม่มีเฟรมเวิร์ก DI นักพัฒนาจะสร้างออบเจ็กต์ด้วยตนเองผ่านคอนสตรัคเตอร์หรือโรงงาน โดยส่งต่อพึ่งพาไปตามสายโซ่ ความต้องการใหม่แต่ละอย่างหมายถึงการเปลี่ยนแปลงลายเซ็นของคอนสตรัคเตอร์ทั้งหมดในสายโซ่ Dagger ทำให้กระบวนการนี้เป็นอัตโนมัติ: คุณเพียงแค่ประกาศว่าต้องการประเภทใด (@Inject constructor) และ Dagger จะสร้างกราฟพึ่งพา แก้ไขประเภทที่ซ้อนกันทั้งหมด เมื่อพึ่งพาเปลี่ยนแปลง Dagger จะอัปเดตโค้ดที่สร้างขึ้นโดยอัตโนมัติ — เป็นไปไม่ได้ที่จะทำผิดพลาดในสายโซ่

หลักการของการฉีดพึ่งพา

การฉีดพึ่งพา คือรูปแบบที่ออบเจ็กต์ได้รับการพึ่งพาจากภายนอกแทนที่จะสร้างขึ้นเอง DI ใช้หลักการ Inversion of Control (IoC): คลาสไม่รับผิดชอบในการสร้างพึ่งพาของตัวเอง แต่ประกาศผ่านคอนสตรัคเตอร์ เมธอด หรือฟิลด์ การฉีดผ่านคอนสตรัคเตอร์ถือเป็นวิธีที่ต้องการมากที่สุดเพราะรับประกันว่าออบเจ็กต์ถูกสร้างขึ้นในสถานะที่ถูกต้อง

ประเภทการฉีดไวยากรณ์ Daggerเมื่อใดควรใช้
Constructor injection@Inject constructorวิธีหลัก — สำหรับคลาสที่กำหนดเองทั้งหมด
Field injection@Inject lateinit varเฉพาะคอมโพเนนต์ Android (Activity, Fragment)
Method injection@Inject fun bind()สำหรับการเริ่มต้นหลังการสร้าง

ข้อดีของ DI แบบคอมไพล์ไทม์

ข้อดีหลักของ DI ได้แก่ ความสามารถในการทดสอบ (พึ่งพาสามารถถูกแทนที่ด้วยออบเจ็กต์ mock), การเชื่อมโยงแบบหลวม (คลาสพึ่งพาอินเทอร์เฟซ ไม่ใช่การนำไปใช้), และการจัดการวงจรชีวิตของออบเจ็กต์อย่างชัดเจนผ่านสโคป Dagger รับประกันโดยอัตโนมัติว่าออบเจ็กต์ถูกสร้างขึ้นครั้งเดียวภายในสโคปของมันและถูกทำลายเมื่อออกจากสโคป

สถาปัตยกรรม Dagger: Component, Module, Provides

Component คือองค์ประกอบหลักของกราฟพึ่งพาของ Dagger มันคืออินเทอร์เฟซที่กำกับด้วย @Component ซึ่งอธิบายสะพานระหว่าง Module และเป้าหมายการฉีด Dagger สร้างการนำไปใช้ของ Component (เช่น DaggerAppComponent) ในเวลาคอมไพล์ Component กำหนดว่าประเภทใดบ้างที่พร้อมสำหรับการฉีดผ่านเมธอดนามธรรมที่ส่งคืนประเภทที่ต้องการ หรือผ่านเมธอด inject ที่รับออบเจ็กต์สำหรับการฉีดฟิลด์

kotlin
// Module: ให้พึ่งพาที่ Dagger ไม่สามารถสร้างได้เอง
@Module
class NetworkModule {
    @Provides
    @Singleton
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .build()
    }

    @Provides
    @Singleton
    fun provideApiService(client: OkHttpClient): ApiService {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
    }
}

// Component: เชื่อมต่อ Module และเป้าหมาย Injection
@Component(modules = [NetworkModule::class])
interface AppComponent {
    fun inject(activity: MainActivity)
    fun getApiService(): ApiService
}

@Module คือคลาสที่มีเมธอดพร้อม @Provides ซึ่งส่งคืนอินสแตนซ์ของพึ่งพา Module ใช้สำหรับประเภทที่ Dagger ไม่สามารถสร้างได้โดยอัตโนมัติ: ไลบรารีบุคคลที่สาม (OkHttp, Retrofit), ออบเจ็กต์ที่มีพารามิเตอร์คอนสตรัคเตอร์, อินเทอร์เฟซที่มีการเลือกการนำไปใช้ @Binds เป็นทางเลือกแทน @Provides สำหรับกรณีที่เมธอดส่งคืนอินเทอร์เฟซและรับการนำไปใช้เดียว: Dagger สร้างแคสต์โดยตรงโดยไม่เรียกเมธอด

@Scope กำหนดอายุการใช้งานของออบเจ็กต์ในกราฟพึ่งพา @Singleton — ออบเจ็กต์ถูกสร้างขึ้นครั้งเดียวสำหรับทั้งแอปพลิเคชัน @ActivityScoped — ออบเจ็กต์มีชีวิตอยู่ตราบเท่าที่ Activity มีชีวิต @FragmentScoped — ตราบเท่าที่ Fragment มีชีวิต หากไม่มีสโคป Dagger จะสร้างอินสแตนซ์ใหม่ทุกครั้งที่มีการฉีด @Reusable — สโคปสำหรับออบเจ็กต์ที่ไม่จำเป็นต้องเป็นซิงเกิลตันแต่การสร้างมีต้นทุนสูง — Dagger อาจแคชอินสแตนซ์แต่ไม่รับประกัน

Hilt สำหรับ Android: @HiltAndroidApp และ @AndroidEntryPoint

Hilt ทำให้การกำหนดค่า Dagger สำหรับ Android ง่ายขึ้นผ่านคอมโพเนนต์ที่กำหนดไว้ล่วงหน้าและการสร้างกราฟพื้นฐานอัตโนมัติ คำอธิบายประกอบ @HiltAndroidApp บนคลาส Application เริ่มต้นการสร้างคอมโพเนนต์ Hilt หากไม่มีคำอธิบายประกอบนี้ Hilt จะไม่ทำงาน — มันบังคับสำหรับแอปพลิเคชัน Android ใดๆ ที่ใช้ Hilt @HiltAndroidApp สร้างคอมโพเนนต์หลัก SingletonComponent ซึ่งคอมโพเนนต์อื่นๆ ทั้งหมดของแอปพลิเคชันสืบทอด

kotlin
@HiltAndroidApp
class MyApplication : Application()

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    @Inject lateinit var apiService: ApiService

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // apiService ถูกฉีดแล้วก่อนการเรียก onCreate
    }
}

@Module
@InstallIn(SingletonComponent::class)
class AppModule {
    @Provides
    @Singleton
    fun provideDatabase(@ApplicationContext ctx: Context): AppDatabase {
        return Room.databaseBuilder(ctx, AppDatabase::class.java, "app.db").build()
    }
}

@AndroidEntryPoint คือคำอธิบายประกอบสำหรับ Activity, Fragment, Service, BroadcastReceiver และ View มันสร้างคอมโพเนนต์ Hilt สำหรับแต่ละประเภท: @AndroidEntryPoint บน Activity สร้าง ActivityComponent ที่สืบทอดจาก SingletonComponent คอมโพเนนต์ลูกได้รับพึ่งพาทั้งหมดของพ่อแม่โดยอัตโนมัติ การฉีดฟิลด์ด้วย @Inject lateinit var ใช้ได้เฉพาะในคลาสที่กำกับด้วย @AndroidEntryPoint — ในคลาสปกติจะใช้การฉีดคอนสตรัคเตอร์

@InstallIn ระบุว่าคอมโพเนนต์ Hilt ใดที่โมดูลถูกติดตั้ง NetworkModule ที่มี @InstallIn(SingletonComponent::class) ใช้ได้ทั่วทั้งแอปพลิเคชัน Module ที่มี @InstallIn(ActivityComponent::class) ใช้ได้เฉพาะใน Activity เท่านั้น ซึ่งแยกกราฟพึ่งพา: โมดูลเฉพาะ Activity จะไม่ปรากฏใน Fragment และ ViewModel ป้องกันการใช้พึ่งพาที่ไม่ถูกต้องโดยไม่ได้ตั้งใจ @ApplicationContext คือตัวระบุคุณภาพในตัวของ Hilt สำหรับรับ Context ของแอปพลิเคชัน

Qualifier: @Named และตัวระบุคุณภาพที่กำหนดเอง

เมื่อจำเป็นต้องฉีดการนำไปใช้สองแบบที่แตกต่างกันของอินเทอร์เฟซเดียวกัน จะใช้ตัวระบุคุณภาพ Hilt รองรับ @Named สำหรับตัวระบุสตริงและคำอธิบายประกอบที่กำหนดเองด้วย @Qualifier ตัวอย่างเช่น @Named("baseUrl") และ @Named("imageBaseUrl") สำหรับการกำหนดค่าสตริงที่แตกต่างกัน ตัวระบุคุณภาพที่กำหนดเองดีกว่า @Named เนื่องจากการตรวจสอบในเวลาคอมไพล์ — ชื่อสตริงที่ไม่ถูกต้องจะไม่ถูกตรวจจับจนกว่ารันไทม์

Hilt ViewModel: @HiltViewModel และ @Inject constructor

@HiltViewModel คือคำอธิบายประกอบที่แทนที่ ViewModelProvider.Factory แบบแมนนวล คลาสที่กำกับด้วย @HiltViewModel ที่มี @Inject constructor จะได้รับพึ่งพาทั้งหมดโดยอัตโนมัติผ่าน Dagger Hilt สร้าง ViewModelFactory ที่ใช้โดย Jetpack ViewModelProvider หากไม่มี Hilt นักพัฒนาจะต้องเขียนโรงงานด้วยตนเอง โดยส่งพารามิเตอร์แต่ละตัวจาก Activity หรือ fragment

kotlin
@HiltViewModel
class MainViewModel
    @Inject constructor(
        private val apiService: ApiService,
        private val database: AppDatabase
    ) : ViewModel() {

    private val _users = MutableStateFlow<List<User>>(emptyList())
    val users: StateFlow<List<User>> = _users.asStateFlow()

    fun loadUsers() {
        viewModelScope.launch {
            _users.value = apiService.getUsers()
        }
    }
}

// ใน Activity — Hilt สร้าง ViewModel โดยอัตโนมัติ
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    private val viewModel: MainViewModel by viewModels()
}

ViewModelScoped คือสโคปของ Hilt สำหรับพึ่งพาที่มีชีวิตอยู่ตราบเท่าที่ ViewModel มีชีวิต ถ้า ViewModel สองตัวที่มีประเภทเดียวกันฉีดพึ่งพา @ViewModelScoped เดียวกัน แต่ละตัวจะได้รับอินสแตนซ์ของตัวเอง ซึ่งแยกความแตกต่าง @ViewModelScoped ออกจาก @ActivityScoped ที่ Activity หนึ่งตัวได้รับอินสแตนซ์เดียวสำหรับทั้งหมด fragment สำหรับพึ่งพาเฉพาะ ViewModel (เช่น SavedStateHandle) จะใช้ @HiltViewModel กับ @Inject constructor(savedStateHandle: SavedStateHandle)

Hilt รองรับ การฉีดแบบช่วยเหลือ ผ่านไลบรารี Hilt Extensions การฉีดแบบช่วยเหลือช่วยให้ส่งพารามิเตอร์ไปยังคอนสตรัคเตอร์ในเวลาที่ฉีดเมื่อพึ่งพาบางอย่างรู้จักเฉพาะในรันไทม์ (เช่น ID ผู้ใช้จาก intent) สำหรับการฉีดแบบช่วยเหลือ ใช้ @AssistedInject ร่วมกับพารามิเตอร์ @Assisted Hilt สร้าง AssistedFactory ที่สามารถฉีดได้ด้วยวิธีมาตรฐาน

Dagger vs Hilt: การเปรียบเทียบและการย้ายระบบ

Dagger บริสุทธิ์ ต้องการการสร้าง Component ด้วยตนเอง การกำหนดสโคป และการกำหนดค่าการฉีดในแต่ละคอมโพเนนต์ Android นักพัฒนาสร้าง AppComponent, ActivityComponent, FragmentComponent และจัดการความสัมพันธ์ผ่าน @Subcomponent วิธีการนี้ให้การควบคุมสูงสุดแต่ต้องใช้โค้ดโครงสร้างพื้นฐานจำนวนมาก Dagger ใช้ในโปรเจกต์ขนาดใหญ่ที่ต้องการสถาปัตยกรรม DI ที่ไม่ได้มาตรฐาน หรือในโปรเจกต์ Java/Kotlin ที่ไม่ใช่ Android

Hilt ทำให้โค้ดโครงสร้างพื้นฐานเป็นอัตโนมัติ: หนึ่ง @HiltAndroidApp, หนึ่ง @AndroidEntryPoint สำหรับแต่ละคอมโพเนนต์, สโคปที่กำหนดไว้ล่วงหน้า Google แนะนำ Hilt สำหรับโปรเจกต์ Android ใหม่ทั้งหมด การย้ายระบบจาก Dagger ไปยัง Hilt รวมถึงการแทนที่ Component ด้วย @InstallIn, การแทนที่ @Subcomponent ด้วยคอมโพเนนต์ Hilt ที่กำหนดไว้ล่วงหน้า และการแทนที่ ViewModelProvider.Factory แบบแมนนวลด้วย @HiltViewModel คลาส @Module ส่วนใหญ่ถูกย้ายโดยการเพิ่ม @InstallIn โดยไม่เปลี่ยนเมธอด @Provides

คุณลักษณะDaggerHilt
การตั้งค่าด้วยตนเอง: Component, Subcomponent, Builderอัตโนมัติ: @HiltAndroidApp, @AndroidEntryPoint
คอมโพเนนต์ Androidไม่มีการกำหนดไว้ล่วงหน้า12+ คอมโพเนนต์ในตัว
ViewModelโรงงานด้วยตนเอง@HiltViewModel + @Inject constructor
หลายโมดูลผ่าน @Component(dependencies)ผ่าน @InstallIn + การรวม
ความซับซ้อนสูง — ต้องใช้ประสบการณ์ต่ำ — เข้าใจได้โดยสัญชาตญาณ
ความยืดหยุ่นสูงสุดมาตรฐาน (ครอบคลุม 95% ของสถานการณ์)

ข้อจำกัดของ Hilt: ไลบรารีรองรับเฉพาะ Android (ไม่เหมาะสำหรับโปรเจกต์ Java ฝั่งเซิร์ฟเวอร์บริสุทธิ์), บังคับโครงสร้างคอมโพเนนต์บางอย่าง (ยากที่จะแทนที่), และเพิ่มการพึ่งพา android.hilt:hilt-navigation-compose สำหรับโปรเจกต์ Jetpack Compose สำหรับแอปพลิเคชัน Compose Hilt มี @HiltViewModel ที่เข้าถึงได้ใน Composable ผ่าน hiltViewModel() — โดยไม่ต้องส่ง ViewModel ด้วยตนเองจาก Activity

คำถามที่พบบ่อย

Dagger และ Hilt แตกต่างกันอย่างไร?

Dagger คือเฟรมเวิร์ก DI พื้นฐานแบบคอมไพล์ไทม์ที่มีการกำหนดค่า Component และ Module ด้วยตนเอง Hilt คือชั้นครอบ Android ที่ทำให้การสร้างคอมโพเนนต์และการรวมกับวงจรชีวิตของ Activity, Fragment, ViewModel, Service และ BroadcastReceiver เป็นอัตโนมัติ

ทำไมต้องใช้ @HiltAndroidApp?

@HiltAndroidApp เปิดใช้งานการสร้างคอมโพเนนต์ Hilt สำหรับ Application หากไม่มีคำอธิบายประกอบนี้ Hilt จะไม่สามารถสร้าง SingletonComponent พื้นฐานที่ ActivityComponent, FragmentComponent และ ViewModelComponent ทั้งหมดสืบทอดได้ คำอธิบายประกอบนี้บังคับสำหรับโปรเจกต์ Hilt ใดๆ

Hilt ทำงานกับ Jetpack Navigation อย่างไร?

Hilt Navigation มี @HiltViewModel สำหรับ ViewModel ใน NavBackStackEntry และ hiltNavGraphViewModels() สำหรับกำหนดสโคป ViewModel ภายในกราฟนำทาง ไลบรารี android.hilt:hilt-navigation-fragment สร้าง ViewModel โดยอัตโนมัติสำหรับแต่ละ NavBackStackEntry

จะฉีด Context ใน Hilt ได้อย่างไร?

ใช้ @ApplicationContext สำหรับบริบทของแอปพลิเคชัน หรือ @ActivityContext สำหรับบริบทของ Activity Hilt มีตัวระบุคุณภาพเหล่านี้ในตัวในไลบรารี android.hilt:hilt-android @ActivityContext ใช้ได้เฉพาะในโมดูลที่ติดตั้งใน ActivityComponent เท่านั้น

@Binds คืออะไรและใช้เมื่อใด?

@Binds เป็นทางเลือกที่มีประสิทธิภาพแทน @Provides เมื่อเมธอดรับพารามิเตอร์หนึ่งตัวพอดีและส่งคืนประเภทของมันเป็นอินเทอร์เฟซ @Binds สร้างแคสต์โดยตรงโดยไม่เรียกเมธอด ลดปริมาณโค้ดที่สร้างขึ้นและปรับปรุงประสิทธิภาพการฉีด

สรุป

  • Dagger — เฟรมเวิร์ก DI แบบคอมไพล์ไทม์พร้อมคำอธิบายประกอบ @Module, @Provides, @Component และการสร้างโค้ดผ่าน APT
  • Hilt — ชั้นครอบ Android บน Dagger พร้อม @HiltAndroidApp, @AndroidEntryPoint, @InstallIn และคอมโพเนนต์ที่กำหนดไว้ล่วงหน้า
  • Component จัดการกราฟพึ่งพา, Module มีคลาสบุคคลที่สาม, Provides มีโรงงานออบเจ็กต์
  • Scope (@Singleton, @ViewModelScoped, @ActivityScoped) กำหนดอายุออบเจ็กต์ในกราฟ Dagger
  • @HiltViewModel ทำให้การสร้าง ViewModel เป็นอัตโนมัติ กำจัดโรงงาน ViewModelProvider.Factory แบบแมนนวล
  • @InstallIn แยกโมดูลตามคอมโพเนนต์ ป้องกันการรั่วไหลของพึ่งพาระหว่างชั้นแอปพลิเคชัน
  • Hilt ได้รับการแนะนำโดย Google สำหรับโปรเจกต์ Android ใหม่ทั้งหมด, Dagger สำหรับสถาปัตยกรรม DI ที่ไม่ใช่ Android และแบบกำหนดเอง

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม