Koin — คืออะไร หลักการ Dependency Injection และทำงานอย่างไร

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

Koin คือเฟรมเวิร์ก DI สำหรับ Kotlin ที่ทำงานโดยไม่ต้องสร้างโค้ด ใช้รีเฟลกชันหรือคำอธิบายประกอบ ไลบรารีใช้ DSL เพื่ออธิบายโมดูลและฉีด dependencies ผ่านคอนเทนเนอร์น้ำหนักเบาที่รองรับ Android, Ktor และ Multiplatform ตาม เอกสารทางการของ Koin เฟรมเวิร์กมีโมดูล สโคป และการสนับสนุนในตัวสำหรับ Jetpack Compose ด้วย boilerplate น้อยที่สุด

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

  • Koin คือเฟรมเวิร์ก DI สำหรับ Kotlin ที่ใช้ DSL โดยไม่ต้องรีเฟลกชันหรือสร้างโค้ด
  • โมดูล คือการจัดกลุ่มเชิงตรรกะของการลงทะเบียน dependencies ผ่านฟังก์ชัน single และ factory
  • single ลงทะเบียนซิงเกิลตันซึ่งสร้างอินสแตนซ์เพียงครั้งเดียว
  • factory สร้างอินสแตนซ์ใหม่ในทุกคำขอ
  • สโคป คือกลไกในการผูกอายุของ dependency เข้ากับคอมโพเนนต์ เช่น Activity

Koin คืออะไรและแตกต่างอย่างไร

Koin คือเฟรมเวิร์ก DI สำหรับ Kotlin ที่เขียนด้วยภาษาบริสุทธิ์โดยไม่ต้องใช้รีเฟลกชัน คำอธิบายประกอบหรือการสร้างโค้ด แตกต่างจาก Dagger Hilt ที่ต้องใช้ตัวประมวลผลคำอธิบายประกอบและการสร้างโค้ดในขณะคอมไพล์ Koin ทำงานเฉพาะในรันไทม์โดยใช้ DSL น้ำหนักเบาเพื่ออธิบายโมดูล

แนวคิดหลักของ Koin คือการให้ API ที่เรียบง่ายสำหรับการลงทะเบียนและแก้ไข dependencies โดยไม่ต้องเรียนรู้แนวคิดที่ซับซ้อนเกี่ยวกับกราฟ dependencies และแผนภูมิคอมโพเนนต์ นักพัฒนาอธิบายว่าคลาสใดบ้างที่พร้อมใช้งานสำหรับคอนเทนเนอร์ และ Koin จะฉีด dependencies เหล่านั้นโดยอัตโนมัติผ่าน คอนสตรักเตอร์ หรือตัวแทนแบบขี้เกียจ by inject เฟรมเวิร์กเข้ากันได้อย่างสมบูรณ์กับ Kotlin Multiplatform ทำให้สามารถใช้วิธีการ DI แบบเดียวกันบน Android, iOS และฝั่งเซิร์ฟเวอร์

ตามการสำรวจของ Kotlin Developers Community (2025) Koin ถูกใช้ใน 31% ของโปรเจกต์ Android เชิงพาณิชย์ รองจาก Hilt (47%) เท่านั้น เหตุผลหลักในการเลือกคือการตั้งค่าง่ายและไม่จำเป็นต้องสร้างโค้ด ซึ่งช่วยเร่งการคอมไพล์โปรเจกต์

เลือก Koin สำหรับโปรเจกต์ขนาดกลางและใหญ่ที่ต้องการการเริ่มต้นพัฒนาที่รวดเร็ว หรือสำหรับโซลูชัน Kotlin Multiplatform ที่ Hilt ไม่พร้อมใช้งานด้วยเหตุผลทางสถาปัตยกรรม

Koin ไม่ใช้รีเฟลกชันหรือการสร้างโค้ด — การลงทะเบียนทั้งหมดสร้างขึ้นบนฟังก์ชัน inline พร้อมชนิด reified ที่แทนที่ชนิดที่เป็นรูปธรรมลงในเนื้อหาของฟังก์ชันในขณะคอมไพล์ สิ่งนี้ทำให้ Koin เป็นหนึ่งในเฟรมเวิร์ก DI ที่เบาที่สุดในแง่ของขนาด APK สุดท้าย: การเพิ่ม Koin ทำให้ขนาดแอปพลิเคชันเพิ่มขึ้นเพียง 100-150 KB ในขณะที่ Dagger Hilt เพิ่มประมาณ 500 KB เนื่องจากโค้ดที่สร้างขึ้น

คอนเทนเนอร์และ DSL ของ Koin ทำงานอย่างไร

คอนเทนเนอร์ Koin เริ่มต้นผ่านฟังก์ชัน startKoin ซึ่งรับแลมบ์ดาพร้อมการกำหนดค่า ภายในแลมบ์ดานี้ โมดูลที่มีการลงทะเบียน — ส่วนประกอบหลักของตรรกะ DI — จะถูกอธิบาย

startKoin และโมดูล

ฟังก์ชัน startKoin สร้างคอนเทนเนอร์ส่วนกลางที่สามารถเข้าถึงได้จากทุกที่ในแอปพลิเคชันผ่าน GlobalContext อย่างไรก็ตามในโปรเจกต์แบบหลายโมดูล แนะนำให้ใช้ KoinApplication เพื่อสร้างคอนเทนเนอร์ที่แยกออกจากกัน ใน Android ใช้ AndroidContext สำหรับการเริ่มต้น ซึ่งผูกกับวงจรชีวิตของ Application โดยอัตโนมัติ โมดูลถูกลงทะเบียนผ่านพารามิเตอร์ modules ซึ่งรับรายการอินสแตนซ์ของ Module

kotlin
val networkModule = module {
    single {
        OkHttpClient()
    }
    single {
        Retrofit.Builder()
            .baseUrl("https://api.example.com")
            .build()
    }
}

startKoin {
    modules(networkModule)
}

แต่ละโมดูลมีคำจำกัดความผ่าน single (ซิงเกิลตัน) หรือ factory (อินสแตนซ์ใหม่) คำจำกัดความสามารถอ้างอิงถึง dependencies ที่ลงทะเบียนอื่นผ่าน get() ทำให้เกิดกราฟการฉีดโดยไม่ต้องระบุชนิดอย่างชัดเจนและไม่มีโค้ด boilerplate

DSL และฟังก์ชัน inline

Koin ใช้ฟังก์ชัน inline พร้อมพารามิเตอร์ reified อย่างแข็งขันสำหรับการอนุมานชนิดจากบริบท ซึ่งช่วยให้เขียนการลงทะเบียนโดยไม่ต้องระบุคลาสอย่างชัดเจน: single { MyService() } จะกำหนดชนิดโดยอัตโนมัติจากค่าที่ส่งคืนของแลมบ์ดา

แตกต่างจาก Dagger ตรงที่ Koin ไม่ตรวจสอบกราฟ dependencies ในขณะคอมไพล์ — ข้อผิดพลาดทั้งหมดจะถูกตรวจพบในรันไทม์เมื่อเข้าถึง dependency ที่ยังไม่ได้รับการแก้ไขครั้งแรก นี่คือการแลกเปลี่ยนที่ทำให้โค้ดง่ายขึ้นอย่างมากและเร่งการคอมไพล์ แต่ต้องมีการครอบคลุมการทดสอบของการกำหนดค่า DI หลายทีมเลือก Koin เนื่องจากความเร็วในการพัฒนาและความเรียบง่าย แม้จะไม่มีการตรวจสอบในขณะคอมไพล์

ใน Koin เวอร์ชัน 3.5 มีการตรวจสอบกราฟในขณะคอมไพล์แบบทดลองผ่านปลั๊กอิน Koin Annotations นักพัฒนาเพิ่มคำอธิบายประกอบ @Module และ @KoinComponent และปลั๊กอินสร้างโค้ดการตรวจสอบที่ทำงานระหว่างการคอมไพล์ อย่างไรก็ตาม ข้อได้เปรียบหลักของ Koin — ไม่มีการสร้างโค้ด — จะหายไปในโหมดนี้ ดังนั้นทีมส่วนใหญ่ยังคงใช้วิธีการ DSL แบบคลาสสิกพร้อมการตรวจสอบรันไทม์ผ่านการทดสอบ

วิธีการฉีด dependencies ใน Koin

Koin มีหลายวิธีในการฉีด dependencies: by inject(), get() และการส่งผ่านคอนสตรักเตอร์โดยตรง การเลือกขึ้นอยู่กับบริบทการใช้งาน

by inject() — การฉีดแบบขี้เกียจ

ตัวแทน by inject เป็นวิธีการฉีดที่พบมากที่สุดใน ViewModel และแฟรกเมนต์ Android dependency จะเริ่มต้นแบบขี้เกียจ — เฉพาะเมื่อมีการเข้าถึงคุณสมบัติครั้งแรกเท่านั้น ซึ่งมีประสิทธิภาพสำหรับบริการที่ใช้ทรัพยากรมากซึ่งอาจไม่จำเป็นทันที

kotlin
class MainViewModel : ViewModel() {
    private val repository: UserRepository by inject()

    fun loadUsers() {
        repository.fetchAll()
    }
}

get() — การรับอย่างชัดแจ้ง

ฟังก์ชัน get ส่งคืนอินสแตนซ์ dependency ทันที ใช้ภายในแลมบ์ดา factory ระหว่างการลงทะเบียนหรือเมื่อต้องการ dependency ในบริบทแบบซิงโครนัสโดยไม่ต้องเริ่มต้นแบบขี้เกียจ แตกต่างจาก by inject() ตรงที่ get() ไม่รองรับการโหลดแบบขี้เกียจและต้องการให้คอนเทนเนอร์เริ่มต้นแล้วในขณะที่เรียก

โมดูลและสโคปใน Koin

สโคป ใน Koin คือกลไกในการผูกอายุของ dependencies เข้ากับคอมโพเนนต์เฉพาะ เช่น Activity, Fragment หรือเซสชันที่กำหนดเอง นี่คือฟังก์ชันหลักสำหรับการจัดการหน่วยความจำในแอปพลิเคชัน Android

scope — การผูกกับคอมโพเนนต์

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

kotlin
val userScope = module {
    scope<UserSession> {
        scoped {
            UserRepository(get())
        }
        scoped {
            SessionManager(get())
        }
    }
}

ฟังก์ชัน scoped ลงทะเบียน dependency ที่จะมีอยู่ภายในสโคปเท่านั้น เมื่อปิดสโคป ออบเจกต์ scoped ทั้งหมดจะพร้อมใช้งานสำหรับตัวเก็บขยะ

single เทียบกับ factory

single ลงทะเบียนอินสแตนซ์เดียวสำหรับทั้งแอปพลิเคชันด้วยการเริ่มต้นแบบขี้เกียจ ใช้สำหรับบริการไร้สถานะ: ไคลเอนต์เครือข่าย, แคช, ตัวบันทึก

factory สร้างอินสแตนซ์ใหม่ทุกครั้งที่เรียก get() ใช้กับ ViewModel ที่เก็บข้อมูล และออบเจกต์ที่มีสถานะซึ่งต้องการอินสแตนซ์ใหม่ทุกครั้งที่เข้าถึง

Koin ในโปรเจกต์ Android

การรวม Koin เข้ากับโปรเจกต์ Android นั้นน้อยมาก: เพียงเพิ่ม dependency ใน build.gradle และเรียก startKoin ใน Application.onCreate Koin มีโมดูลสำหรับการรวมกับ Jetpack Compose, Navigation และ WorkManager ทำให้เป็นทางเลือกที่สมบูรณ์สำหรับ Hilt

ไลบรารีพิเศษ koin-android-compose ช่วยให้สามารถฉีด dependencies โดยตรงในฟังก์ชัน Composable ผ่าน koinViewModel() และ koinInject() สิ่งนี้ช่วยลดความจำเป็นในการส่งคอนเทนเนอร์ผ่านพารามิเตอร์ของแต่ละหน้าจอและทำให้โค้ด ViewModel สะอาดขึ้นผ่านการผูกวงจรชีวิตอัตโนมัติ

ตาม Google I/O 2024 Jetpack Compose กลายเป็นเฟรมเวิร์กหลักสำหรับโปรเจกต์ Android ใหม่ Koin รองรับ Compose โดยกำเนิดโดยไม่ต้องกำหนดค่าเพิ่มเติม ผูกสโคปกับวงจรชีวิต ViewModel โดยอัตโนมัติผ่าน koinViewModel() โดยคำนึงถึง บริบทของ coroutine

สำหรับการทดสอบ Koin มีฟังก์ชัน koinTest และ koinTestRule ซึ่งสร้างคอนเทนเนอร์ทดสอบที่แยกออกมาพร้อมโมดูลทดสอบและปิดโดยอัตโนมัติหลังจากเสร็จสิ้นการทดสอบ สิ่งนี้ช่วยให้การทดสอบแยกออกจากกันและป้องกันการรั่วไหลของสถานะระหว่างกรณีทดสอบ

การรวม Koin กับ Jetpack Navigation ถูกนำไปใช้ผ่านโมดูล koin-androidx-navigation ViewModel ของแต่ละหน้าจอจะได้รับ dependencies โดยอัตโนมัติผ่าน by viewModel() พร้อมการส่ง SavedStateHandle เพื่อรักษาสถานะเมื่อหมุนหน้าจอและกู้คืนหลังจากแอปพลิเคชันถูกระงับ

สำหรับการทดสอบหน่วยของ ViewModel ด้วย Koin ใช้ koinTestRule จากไลบรารี koin-test-junit5 หรือ koin-test-junit4 กฎจะสร้างคอนเทนเนอร์ที่แยกออกมาพร้อมโมดูลทดสอบก่อนการทดสอบแต่ละครั้งและปิดโดยอัตโนมัติหลังจากเสร็จสิ้น ป้องกันการรั่วไหลของสถานะระหว่างกรณีทดสอบ dependencies จริงจะถูกแทนที่ด้วยม็อกผ่าน MockK: โมดูลที่มีการลงทะเบียน single { mockk() } จะแทนที่โมดูลหลัก และ ViewModel ในการทดสอบจะได้รับพฤติกรรมของ dependencies ที่คาดเดาได้

หนึ่งในคุณสมบัติหลักของ Koin 3.x คือการรองรับ Ktor สำหรับการสร้างแอปพลิเคชันเซิร์ฟเวอร์บน Kotlin และ Compose Multiplatform สำหรับแอปพลิเคชันเดสก์ท็อป สิ่งนี้ทำให้ Koin เป็นเฟรมเวิร์ก DI เพียงตัวเดียวที่ครอบคลุมทั้งสามแพลตฟอร์ม Kotlin โดยไม่ต้องเปลี่ยนกระบวนทัศน์การฉีด โมดูล koin-ktor ช่วยให้สามารถลงทะเบียน dependencies ผ่าน install(Koin) ในบล็อก Application และฉีดบริการเข้าไปใน routes ผ่าน by inject() เช่นเดียวกับใน Android สิ่งนี้ทำให้ Koin เป็นโซลูชัน DI สากลสำหรับโปรเจกต์ Kotlin ทุกสถาปัตยกรรม — จากไคลเอนต์มือถือไปจนถึงแบ็คเอนด์เซิร์ฟเวอร์

การรวม Koin กับ Jetpack Navigation ผ่านโมดูล koin-androidx-navigation ช่วยลดความจำเป็นในการสร้าง ViewModelProvider.Factory ด้วยตนเองสำหรับแต่ละหน้าจอ สำหรับโปรเจกต์แบบหลายโมดูล Koin รองรับการโหลดโมดูลแบบขี้เกียจผ่าน loadKoinModules ซึ่งช่วยให้แต่ละ โมดูลคุณลักษณะ เชื่อมต่อการกำหนดค่า DI ของตัวเองได้อย่างอิสระ

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

Koin แตกต่างจาก Dagger Hilt อย่างไร

Koin ทำงานในรันไทม์โดยไม่ต้องสร้างโค้ดหรือคำอธิบายประกอบ ซึ่งช่วยเร่งการคอมไพล์แต่ไม่ตรวจสอบกราฟ dependencies ในขณะคอมไพล์ Hilt สร้างโค้ดในขณะคอมไพล์และจับข้อผิดพลาด DI ได้เร็วกว่า แต่ต้องมีการตั้งค่าที่ซับซ้อนและทำให้การคอมไพล์ช้าลง

Koin รองรับ Kotlin Multiplatform หรือไม่

ใช่ Koin รองรับ Kotlin Multiplatform อย่างสมบูรณ์ ไลบรารี koin-core ทำงานบนทุกแพลตฟอร์ม Kotlin ในขณะที่ koin-android และ koin-compose เพิ่มความสามารถเฉพาะแพลตฟอร์มสำหรับ Android และ iOS ตามลำดับ

วิธีจัดการ dependencies แบบวนซ้ำใน Koin

dependencies แบบ วนซ้ำ ทำให้เกิด StackOverflowError ในรันไทม์ Koin ไม่ตรวจพบโดยอัตโนมัติ วิธีแก้ไขคือการปรับโครงสร้างสถาปัตยกรรม: แยกอินเทอร์เฟซร่วม ใช้รูปแบบ Listener/Observer หรือทำลายวงจรผ่าน factory ด้วยการเริ่มต้นแบบเลื่อนเวลา

ฉันต้องปิดสโคปด้วยตนเองหรือไม่

ใน Android สโคป สามารถผูกกับวงจรชีวิตของ Activity หรือ Fragment ผ่าน AndroidScope เมื่อคอมโพเนนต์ถูกทำลาย Koin จะปิดสโคปที่เกี่ยวข้องโดยอัตโนมัติ ในสโคปที่กำหนดเอง (เซสชันผู้ใช้) การปิดจะทำด้วยตนเองโดยเรียก scope.close

วิธีทดสอบโค้ดด้วย Koin

ใช้ฟังก์ชัน koinTest จากโมดูล koin-test มันสร้างคอนเทนเนอร์ที่แยกออกมาพร้อมโมดูลทดสอบซึ่งจะปิดโดยอัตโนมัติหลังการทดสอบ dependencies จริงจะถูกแทนที่ด้วยม็อกผ่านโมดูลที่ใช้ Mockito หรือ MockK

สรุป

  • Koin คือเฟรมเวิร์ก DI สำหรับ Kotlin พร้อม DSL โดยไม่ต้องรีเฟลกชัน คำอธิบายประกอบหรือการสร้างโค้ด
  • โมดูลจัดกลุ่มการลงทะเบียนผ่าน single (ซิงเกิลตัน) และ factory (อินสแตนซ์ใหม่)
  • startKoin เริ่มต้นคอนเทนเนอร์ส่วนกลางที่เข้าถึงได้ผ่าน by inject() และ get()
  • สโคป ผูกอายุของ dependencies เข้ากับวงจรชีวิตของคอมโพเนนต์ Android
  • การฉีดใน Compose ทำผ่าน koinViewModel() และ koinInject()
  • Koin รองรับ Kotlin Multiplatform ทำให้สามารถใช้วิธีการ DI แบบเดียวกันบนทุกแพลตฟอร์ม
  • ข้อผิดพลาด DI ถูกตรวจพบในรันไทม์ ดังนั้นการครอบคลุมการทดสอบของการกำหนดค่าจึงเป็นสิ่งจำเป็น

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

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

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

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