Android KTX เป็นส่วนหนึ่งของ Android Jetpack

Android KTX คือชุดส่วนขยาย Kotlin ที่มาพร้อมกับ Android Jetpack และไลบรารี Android อื่นๆ ส่วนขยาย KTX มีความกระชับ Kotlin ที่มีเอกลักษณ์เป็น Jetpack, แพลตฟอร์ม Android และ API อื่นๆ วิธีการคือ ส่วนขยายใช้ประโยชน์จากฟีเจอร์ภาษา Kotlin หลายอย่างต่อไปนี้

  • ฟังก์ชันส่วนขยาย
  • พร็อพเพอร์ตี้ของส่วนขยาย
  • แลมบ์ดา
  • พารามิเตอร์ที่มีชื่อ
  • ค่าเริ่มต้นของพารามิเตอร์
  • โครูทีน

ตัวอย่างเช่น เมื่อทำงานกับ SharedPreferences คุณต้อง สร้างเครื่องมือแก้ไข ก่อนจะทำการแก้ไขข้อมูลค่ากำหนดได้ คุณยังต้องสมัคร หรือยืนยันการเปลี่ยนแปลงเหล่านั้นเมื่อคุณแก้ไขเสร็จแล้ว ดังที่ปรากฏใน ตัวอย่าง:

sharedPreferences
        .edit()  // create an Editor
        .putBoolean("key", value)
        .apply() // write to disk asynchronously

Kotlin lambdas เหมาะกับกรณีการใช้งานนี้ที่สุด ทำให้คุณสามารถทดสอบ ที่กระชับยิ่งขึ้นโดยการส่งบล็อกของโค้ดเพื่อเรียกใช้หลังจากที่ตัวแก้ไข ให้เรียกใช้โค้ด จากนั้นปล่อยให้ SharedPreferences API นำการเปลี่ยนแปลงไปใช้ทีละขั้น

นี่คือตัวอย่างฟังก์ชันหนึ่งของ Android KTX Core SharedPreferences.edit ซึ่งจะเพิ่มฟังก์ชันแก้ไขใน SharedPreferences ฟังก์ชันนี้ต้องใช้ Flag boolean ที่ไม่บังคับเป็นอาร์กิวเมนต์แรกที่ระบุว่าจะคอมมิตหรือไม่ หรือนำการเปลี่ยนแปลงไปใช้ และยังได้รับการดำเนินการใน โปรแกรมแก้ไข SharedPreferences ในรูปแบบรูปแลมบ์ดา

// SharedPreferences.edit extension function signature from Android KTX - Core
// inline fun SharedPreferences.edit(
//         commit: Boolean = false,
//         action: SharedPreferences.Editor.() -> Unit)

// Commit a new value asynchronously
sharedPreferences.edit { putBoolean("key", value) }

// Commit a new value synchronously
sharedPreferences.edit(commit = true) { putBoolean("key", value) }

ผู้โทรสามารถเลือกได้ว่าจะคอมมิตหรือใช้การเปลี่ยนแปลง action lambda เป็นฟังก์ชันส่วนขยายแบบไม่ระบุตัวตนใน SharedPreferences.Editor ซึ่งแสดงผล Unit ตามที่เห็นได้จากลายเซ็น นี่คือเหตุผลที่ภายใน คุณจะสามารถทำงานได้โดยตรงใน SharedPreferences.Editor

และสุดท้าย ลายเซ็น SharedPreferences.edit() จะมีคีย์เวิร์ด inline คีย์เวิร์ดนี้จะบอกคอมไพเลอร์ Kotlin ว่าควรคัดลอกและวาง (หรือ inline) ไบต์โค้ดที่คอมไพล์สำหรับฟังก์ชันทุกครั้งที่มีการใช้ฟังก์ชันนั้น การดำเนินการนี้จะหลีกเลี่ยงค่าใช้จ่ายในการดำเนินการสร้างคลาสใหม่ให้กับทุก action แต่ละรายการ เวลาที่เรียกฟังก์ชันนี้

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

ใช้ Android KTX ในโปรเจ็กต์ของคุณ

หากต้องการเริ่มใช้ Android KTX ให้เพิ่มทรัพยากร Dependency ต่อไปนี้ในโปรเจ็กต์ของคุณ build.gradle ไฟล์:

ดึงดูด

repositories {
    google()
}

Kotlin

repositories {
    google()
}

โมดูล AndroidX

Android KTX จัดออกเป็นโมดูลต่างๆ โดยแต่ละโมดูลจะมีอย่างน้อย 1 โมดูล แพ็กเกจของคุณ

คุณต้องใส่ทรัพยากร Dependency สำหรับอาร์ติแฟกต์โมดูลแต่ละรายการในแอป build.gradle ไฟล์ อย่าลืมเพิ่มหมายเลขเวอร์ชันต่อท้ายอาร์ติแฟกต์ คุณดูหมายเลขเวอร์ชันล่าสุดได้ในส่วนที่เกี่ยวข้องของอาร์ติแฟกต์แต่ละรายการ ในหัวข้อนี้

Android KTX มีโมดูลแกนเดี่ยวที่ให้ Kotlin สำหรับ API เฟรมเวิร์กทั่วไปและส่วนขยายเฉพาะโดเมนหลายรายการ

ยกเว้นโมดูลหลัก อาร์ติแฟกต์โมดูล KTX ทั้งหมดจะแทนที่ ทรัพยากร Dependency ของ Java ที่จำเป็นในไฟล์ build.gradle ตัวอย่างเช่น คุณสามารถ แทนที่ทรัพยากร Dependency androidx.fragment:fragment ด้วย androidx.fragment:fragment-ktx ไวยากรณ์นี้ช่วยให้จัดการ การกำหนดเวอร์ชันและไม่ได้เพิ่มข้อกำหนดการประกาศทรัพยากร Dependency เพิ่มเติม

KTX หลัก

โมดูล Core KTX ให้ส่วนขยายสำหรับไลบรารีทั่วไปที่เป็นส่วนหนึ่งของ เฟรมเวิร์กของ Android ไลบรารีเหล่านี้ไม่มีทรัพยากร Dependency แบบ Java คุณต้องเพิ่มลงใน build.gradle

หากต้องการรวมโมดูลนี้ ให้เพิ่มค่าต่อไปนี้ลงในไฟล์ build.gradle ของแอป

ดึงดูด

dependencies {
    implementation "androidx.core:core-ktx:1.13.1"
}

Kotlin

dependencies {
    implementation("androidx.core:core-ktx:1.13.1")
}

รายการแพ็กเกจที่อยู่ในโมดูล Core KTX มีดังนี้

คอลเล็กชัน KTX

ส่วนขยายคอลเล็กชันมีฟังก์ชันยูทิลิตีสำหรับการทำงานร่วมกับ ไลบรารีคอลเล็กชันที่ประหยัดหน่วยความจำ ซึ่งรวมถึง ArrayMap, LongSparseArray LruCache และอื่นๆ

หากต้องการใช้โมดูลนี้ ให้เพิ่มค่าต่อไปนี้ลงในไฟล์ build.gradle ของแอป

ดึงดูด

dependencies {
    implementation "androidx.collection:collection-ktx:1.4.3"
}

Kotlin

dependencies {
    implementation("androidx.collection:collection-ktx:1.4.3")
}

ส่วนขยายคอลเล็กชันใช้ประโยชน์จากโอเปอเรเตอร์ของ Kotlin มากเกินไป ทำให้สิ่งต่างๆ ง่ายขึ้น เช่น การต่อคอลเล็กชัน ดังที่ปรากฏใน ตัวอย่าง:

// Combine 2 ArraySets into 1.
val combinedArraySet = arraySetOf(1, 2, 3) + arraySetOf(4, 5, 6)

// Combine with numbers to create a new sets.
val newArraySet = combinedArraySet + 7 + 8

แฟรกเมนต์ KTX

โมดูล KTX ส่วนย่อย มีส่วนขยายจำนวนมากที่ช่วยให้ Fragment API ง่ายขึ้น

หากต้องการรวมโมดูลนี้ ให้เพิ่มค่าต่อไปนี้ลงในไฟล์ build.gradle ของแอป

ดึงดูด

dependencies {
    implementation "androidx.fragment:fragment-ktx:1.8.2"
}

Kotlin

dependencies {
    implementation("androidx.fragment:fragment-ktx:1.8.2")
}

เมื่อใช้โมดูล Fragment KTX คุณสามารถลดความยุ่งยากในการทำธุรกรรมแบบ Fragment ได้ด้วย lambdas เช่น

fragmentManager().commit {
   addToBackStack("...")
   setCustomAnimations(
           R.anim.enter_anim,
           R.anim.exit_anim)
   add(fragment, "...")
}

คุณยังเชื่อมโยงกับ ViewModel ในบรรทัดเดียวได้โดยใช้ viewModels และ ผู้รับมอบสิทธิ์พร็อพเพอร์ตี้ activityViewModels คน:

// Get a reference to the ViewModel scoped to this Fragment
val viewModel by viewModels<MyViewModel>()

// Get a reference to the ViewModel scoped to its Activity
val viewModel by activityViewModels<MyViewModel>()

วงจรการใช้งาน KTX

Lifecycle KTX กำหนด LifecycleScope สำหรับแต่ละรายการ Lifecycle โครูทีนใดก็ได้ ที่เปิดตัวในขอบเขตนี้จะถูกยกเลิกเมื่อ Lifecycle ถูกทำลาย คุณสามารถ เข้าถึง CoroutineScope ของ Lifecycle โดยใช้ พร็อพเพอร์ตี้ lifecycle.coroutineScope หรือ lifecycleOwner.lifecycleScope

หากต้องการรวมโมดูลนี้ ให้เพิ่มค่าต่อไปนี้ลงในไฟล์ build.gradle ของแอป

ดึงดูด

dependencies {
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.8.4"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.4")
}

ตัวอย่างต่อไปนี้สาธิตวิธีใช้ lifecycleOwner.lifecycleScope เพื่อ สร้างข้อความที่คำนวณล่วงหน้าแบบไม่พร้อมกัน:

class MyFragment: Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewLifecycleOwner.lifecycleScope.launch {
            val params = TextViewCompat.getTextMetricsParams(textView)
            val precomputedText = withContext(Dispatchers.Default) {
                PrecomputedTextCompat.create(longTextContent, params)
            }
            TextViewCompat.setPrecomputedText(textView, precomputedText)
        }
    }
}

LiveData KTX

เมื่อใช้ LiveData คุณอาจต้องคำนวณค่าต่างๆ ไม่พร้อมกัน สำหรับ เช่น คุณอาจต้องการดึงข้อมูลค่ากำหนดของผู้ใช้และแสดงให้ผู้ใช้เห็น UI สำหรับกรณีเหล่านี้ LiveData KTX มีฟังก์ชันเครื่องมือสร้าง liveData ที่ เรียกฟังก์ชัน suspend และแสดงผลลัพธ์เป็นออบเจ็กต์ LiveData

หากต้องการรวมโมดูลนี้ ให้เพิ่มค่าต่อไปนี้ลงในไฟล์ build.gradle ของแอป

ดึงดูด

dependencies {
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.8.4"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.8.4")
}

ในตัวอย่างต่อไปนี้ loadUser() คือฟังก์ชันระงับที่ประกาศไว้ที่อื่น คุณสามารถใช้ฟังก์ชันเครื่องมือสร้าง liveData เพื่อเรียก loadUser() แบบไม่พร้อมกัน จากนั้นใช้ emit() เพื่อแสดงผลลัพธ์ ดังนี้

val user: LiveData<User> = liveData {
    val data = database.loadUser() // loadUser is a suspend function.
    emit(data)
}

ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้โครูทีนร่วมกับ LiveData ได้ที่ ใช้โครูทีนของ Kotlin กับคอมโพเนนต์ของสถาปัตยกรรม

คอมโพเนนต์แต่ละรายการของไลบรารีการนำทางจะมีเวอร์ชัน KTX ของตนเองที่ปรับเปลี่ยน API ให้กระชับยิ่งขึ้นและมี Kotlin-idiomatic

หากต้องการรวมโมดูลเหล่านี้ ให้เพิ่มค่าต่อไปนี้ลงในไฟล์ build.gradle ของแอป

ดึงดูด

dependencies {
    implementation "androidx.navigation:navigation-runtime-ktx:2.7.7"
    implementation "androidx.navigation:navigation-fragment-ktx:2.7.7"
    implementation "androidx.navigation:navigation-ui-ktx:2.7.7"
}

Kotlin

dependencies {
    implementation("androidx.navigation:navigation-runtime-ktx:2.7.7")
    implementation("androidx.navigation:navigation-fragment-ktx:2.7.7")
    implementation("androidx.navigation:navigation-ui-ktx:2.7.7")
}

ใช้ฟังก์ชันส่วนขยายและการมอบสิทธิ์พร็อพเพอร์ตี้เพื่อเข้าถึงปลายทาง อาร์กิวเมนต์และไปยังปลายทาง ดังที่ปรากฏในตัวอย่างต่อไปนี้

class MyDestination : Fragment() {

    // Type-safe arguments are accessed from the bundle.
    val args by navArgs<MyDestinationArgs>()

    ...
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        view.findViewById<Button>(R.id.next)
            .setOnClickListener {
                // Fragment extension added to retrieve a NavController from
                // any destination.
                findNavController().navigate(R.id.action_to_next_destination)
            }
     }
     ...

}

พาเล็ต KTX

โมดูล Palette KTX รองรับ Kotlin ที่มีเอกลักษณ์ในการทำงานกับชุดสี

หากต้องการใช้โมดูลนี้ ให้เพิ่มค่าต่อไปนี้ลงในไฟล์ build.gradle ของแอป

ดึงดูด

dependencies {
    implementation "androidx.palette:palette-ktx:1.0.0"
}

Kotlin

dependencies {
    implementation("androidx.palette:palette-ktx:1.0.0")
}

ตัวอย่างเช่น เมื่อทำงานกับอินสแตนซ์ Palette คุณสามารถเรียกข้อมูล ตัวอย่าง selected สำหรับ target ที่ระบุโดยใช้โอเปอเรเตอร์ get ([ ]):

val palette = Palette.from(bitmap).generate()
val swatch = palette[target]

สตรีมเชิงรับ KTX

โมดูล KTX ของสตรีมแบบรีแอคทีฟช่วยให้คุณสร้างสตรีม LiveData ที่สังเกตได้ได้จาก ผู้เผยแพร่โฆษณา ReactiveStreams

หากต้องการรวมโมดูลนี้ ให้เพิ่มค่าต่อไปนี้ลงในไฟล์ build.gradle ของแอป

ดึงดูด

dependencies {
    implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:2.8.4"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-reactivestreams-ktx:2.8.4")
}

ตัวอย่างเช่น สมมติว่าเป็นฐานข้อมูลที่มีรายชื่อผู้ใช้จำนวนน้อย คุณทำสิ่งต่อไปนี้ได้ โหลดฐานข้อมูลลงในหน่วยความจำ แล้วแสดงข้อมูลผู้ใช้ใน UI ของคุณ เพื่อให้บรรลุเป้าหมาย คุณอาจใช้ RxJava คอมโพเนนต์ Jetpack Room ดึงข้อมูลได้ รายชื่อผู้ใช้เป็น Flowable ในสถานการณ์นี้ คุณต้องจัดการ Rx ด้วย การสมัครรับข้อมูลของผู้เผยแพร่โฆษณาตลอดอายุของส่วนย่อยหรือกิจกรรม

แต่เมื่อใช้ LiveDataReactiveStreams คุณจะสามารถใช้ประโยชน์จาก RxJava และ ที่มีโอเปอเรเตอร์มากมายและฟังก์ชันการกำหนดเวลาทำงาน ไปพร้อมๆ กับทำงานร่วมกับ ความเรียบง่ายของ LiveData ดังที่แสดงในตัวอย่างต่อไปนี้

val fun getUsersLiveData() : LiveData<List<User>> {
    val users: Flowable<List<User>> = dao.findUsers()
    return LiveDataReactiveStreams.fromPublisher(users)
}

ห้อง KTX

ส่วนขยายห้องแชทจะเพิ่มการรองรับ Coroutine สำหรับธุรกรรมฐานข้อมูล

หากต้องการใช้โมดูลนี้ ให้เพิ่มค่าต่อไปนี้ลงในไฟล์ build.gradle ของแอป

ดึงดูด

dependencies {
    implementation "androidx.room:room-ktx:2.6.1"
}

Kotlin

dependencies {
    implementation("androidx.room:room-ktx:2.6.1")
}

นี่คือตัวอย่างที่ปัจจุบันห้องแชทใช้โครูทีน ตัวอย่างแรก ใช้ฟังก์ชัน suspend เพื่อแสดงผลรายการออบเจ็กต์ User รายการ ในขณะที่ฟังก์ชันที่ 2 ใช้ Flow ของ Kotlin เพื่อแสดงผลรายการ User แบบไม่พร้อมกัน โปรดทราบว่าเมื่อใช้ Flow คุณ และแจ้งถึงการเปลี่ยนแปลงในตารางที่ค้นหา

@Query("SELECT * FROM Users")
suspend fun getUsers(): List<User>

@Query("SELECT * FROM Users")
fun getUsers(): Flow<List<User>>

SQLite KTX

ส่วนขยาย SQLite จะรวมโค้ดที่เกี่ยวข้องกับ SQL ไว้ในธุรกรรม จึงช่วยลด Boilerplate

หากต้องการใช้โมดูลนี้ ให้เพิ่มค่าต่อไปนี้ลงในไฟล์ build.gradle ของแอป

ดึงดูด

dependencies {
    implementation "androidx.sqlite:sqlite-ktx:2.4.0"
}

Kotlin

dependencies {
    implementation("androidx.sqlite:sqlite-ktx:2.4.0")
}

ตัวอย่างการใช้ส่วนขยาย transaction เพื่อทำฐานข้อมูล ธุรกรรม:

db.transaction {
    // insert data
}

ดูโมเดล KTX

ไลบรารี ViewModel KTX มีฟังก์ชัน viewModelScope() ที่จะทำให้ เปิดใช้โครูทีนจาก ViewModel ได้ง่ายขึ้น CoroutineScope เชื่อมโยงกับ Dispatchers.Main และจะถูกยกเลิกโดยอัตโนมัติ เมื่อล้าง ViewModel คุณสามารถใช้ viewModelScope() แทน สร้างขอบเขตใหม่สำหรับแต่ละ ViewModel

หากต้องการรวมโมดูลนี้ ให้เพิ่มค่าต่อไปนี้ลงในไฟล์ build.gradle ของแอป

ดึงดูด

dependencies {
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4")
}

ตัวอย่างเช่น ฟังก์ชัน viewModelScope() ต่อไปนี้เปิดใช้โคโรทีน ที่สร้างคำขอเครือข่ายในเทรดเบื้องหลัง ห้องสมุดจะจัดการ การตั้งค่าและการล้างขอบเขตที่เกี่ยวข้อง

class MainViewModel : ViewModel() {
    // Make a network request without blocking the UI thread
    private fun makeNetworkRequest() {
        // launch a coroutine in viewModelScope
        viewModelScope.launch  {
            remoteApi.slowFetch()
            ...
        }
    }

    // No need to override onCleared()
}

KTX ของ WorkManager

WorkManager KTX ให้การสนับสนุนชั้นหนึ่งสำหรับโครูทีน

หากต้องการรวมโมดูลนี้ ให้เพิ่มค่าต่อไปนี้ลงในไฟล์ build.gradle ของแอป

ดึงดูด

dependencies {
    implementation "androidx.work:work-runtime-ktx:2.9.1"
}

Kotlin

dependencies {
    implementation("androidx.work:work-runtime-ktx:2.9.1")
}

แทนที่จะขยายเวลา Worker ตอนนี้คุณสามารถ ขยาย CoroutineWorker ซึ่งมี API ต่างกันเล็กน้อย ตัวอย่างเช่น ถ้าคุณต้องการสร้าง CoroutineWorker ในการดำเนินการบางอย่างเกี่ยวกับเครือข่าย คุณสามารถทำสิ่งต่อไปนี้

class CoroutineDownloadWorker(context: Context, params: WorkerParameters)
        : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result = coroutineScope {
        val jobs = (0 until 100).map {
            async {
                downloadSynchronously("https://www.google.com")
            }
        }

        // awaitAll will throw an exception if a download fails, which
        // CoroutineWorker will treat as a failure
        jobs.awaitAll()
        Result.success()
    }
}

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการใช้ CoroutineWorker โปรดดู Threading in CoroutineWorker

WorkManager KTX ยังเพิ่มฟังก์ชันของส่วนขยายไปยัง Operations และ ListenableFutures เพื่อระงับโครูทีนปัจจุบัน

นี่คือตัวอย่างที่ระงับ Operation แสดงผลโดย enqueue():

// Inside of a coroutine...

// Run async operation and suspend until completed.
WorkManager.getInstance()
        .beginWith(longWorkRequest)
        .enqueue().await()

// Resume after work completes...

โมดูล KTX อื่นๆ

คุณยังรวมโมดูล KTX เพิ่มเติมที่มีอยู่นอก AndroidX ได้ด้วย

KTX ของ Firebase

Firebase SDK สำหรับ Android บางรายการมีไลบรารีส่วนขยาย Kotlin ที่ ช่วยให้คุณเขียนโค้ด Kotlin ที่มีเอกลักษณ์ได้เมื่อใช้ Firebase ในแอป สำหรับ ข้อมูลเพิ่มเติม โปรดดูหัวข้อต่อไปนี้

KTX สำหรับ Google Maps Platform

มีส่วนขยาย KTX สำหรับ Android SDK ของ Google Maps Platform ซึ่ง ช่วยให้คุณใช้ประโยชน์จากฟีเจอร์ภาษา Kotlin มากมาย เช่น ส่วนขยาย ฟังก์ชัน พารามิเตอร์ที่มีชื่อ และอาร์กิวเมนต์เริ่มต้น การประกาศทำลายโครงสร้าง และโครูทีน สำหรับข้อมูลเพิ่มเติม โปรดดูหัวข้อต่อไปนี้

Play Core KTX

Play Core KTX เพิ่มการรองรับโครูทีนของ Kotlin สำหรับคำขอแบบครั้งเดียวและโฟลว์ เพื่อการตรวจสอบการอัปเดตสถานะด้วยการเพิ่มฟังก์ชันของส่วนขยายไปยัง SplitInstallManager และ AppUpdateManager ในคลัง Play Core

หากต้องการรวมโมดูลนี้ ให้เพิ่มค่าต่อไปนี้ลงในไฟล์ build.gradle ของแอป

ดึงดูด

dependencies {
    implementation "com.google.android.play:core-ktx:1.8.1"
}

Kotlin

dependencies {
    implementation("com.google.android.play:core-ktx:1.8.1")
}

ต่อไปนี้คือตัวอย่างของการตรวจสอบสถานะ Flow

// Inside of a coroutine...

// Request in-app update status updates.
manager.requestUpdateFlow().collect { updateResult ->
    when (updateResult) {
        is AppUpdateResult.Available -> TODO()
        is AppUpdateResult.InProgress -> TODO()
        is AppUpdateResult.Downloaded -> TODO()
        AppUpdateResult.NotAvailable -> TODO()
    }
}

ข้อมูลเพิ่มเติม

ดูข้อมูลเพิ่มเติมเกี่ยวกับ Android KTX ได้ที่วิดีโอ DevBytes

หากต้องการรายงานปัญหาหรือแนะนำฟีเจอร์ ให้ใช้ เครื่องมือติดตามปัญหา Android KTX