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

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

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

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

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

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

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

// 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 ว่าควรคัดลอกและวาง (หรือในบรรทัด) ไบต์โค้ดที่คอมไพล์สำหรับฟังก์ชันดังกล่าวทุกครั้งที่ใช้ฟังก์ชันดังกล่าว วิธีนี้จะช่วยหลีกเลี่ยงค่าใช้จ่ายเพิ่มเติมในการสร้างอินสแตนซ์ของคลาสใหม่สำหรับ action แต่ละรายการทุกครั้งที่มีการเรียกใช้ฟังก์ชันนี้

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

ใช้ Android KTX ในโปรเจ็กต์

หากต้องการเริ่มใช้ Android KTX ให้เพิ่มการพึ่งพาต่อไปนี้ลงในไฟล์ build.gradle ของโปรเจ็กต์

GroovyKotlin
repositories {
    google()
}
repositories {
    google()
}

โมดูล AndroidX

Android KTX จัดระเบียบเป็นโมดูล โดยแต่ละโมดูลจะมีแพ็กเกจอย่างน้อย 1 รายการ

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

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

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

Core KTX

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

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

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

ต่อไปนี้คือรายการแพ็กเกจที่อยู่ในโมดูล KTX หลัก

คอลเล็กชัน KTX

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

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

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

ส่วนขยายคอลเล็กชันใช้ประโยชน์จากโอเปอเรเตอร์ของ 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 ของ Fragment

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

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

ดึงดูดKotlin
dependencies {
    implementation
"androidx.fragment:fragment-ktx:1.8.3"
}
dependencies {
    implementation
("androidx.fragment:fragment-ktx:1.8.3")
}

โมดูล KTX ของส่วนช่วยให้คุณทําธุรกรรมของส่วนย่อยได้ง่ายขึ้นด้วยแลมดา เช่น

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>()

Lifecycle KTX

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

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

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

ตัวอย่างต่อไปนี้แสดงวิธีใช้ 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 ของแอป

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

ในตัวอย่างต่อไปนี้ 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 มากขึ้น

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

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

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

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)
            }
     }
     ...

}

Palette KTX

โมดูล Palette KTX รองรับรูปแบบโค้ด Kotlin สำหรับการทำงานกับชุดสี

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

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

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

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

Reactive Streams KTX

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

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

ดึงดูดKotlin
dependencies {
    implementation
"androidx.lifecycle:lifecycle-reactivestreams-ktx:2.8.7"
}
dependencies {
    implementation
("androidx.lifecycle:lifecycle-reactivestreams-ktx:2.8.7")
}

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

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

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

ห้อง KTX

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

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

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

ต่อไปนี้เป็นตัวอย่างบางส่วนที่ Room ใช้ coroutine ในปัจจุบัน ตัวอย่างแรกใช้ฟังก์ชัน suspend เพื่อแสดงผลรายการออบเจ็กต์ User ขณะที่อีกตัวอย่างหนึ่งใช้ 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 ไว้ในธุรกรรม ทำให้ไม่ต้องใช้โค้ดสำเร็จรูปจำนวนมาก

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

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

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

db.transaction {
    // insert data
}

ดูโมเดล KTX

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

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

ดึงดูดKotlin
dependencies {
    implementation
"androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.5"
}
dependencies {
    implementation
("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.5")
}

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

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 ของแอป

ดึงดูดKotlin
dependencies {
    implementation
"androidx.work:work-runtime-ktx:2.9.1"
}
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 ได้ที่การแยกเธรดใน 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 สำหรับ SDK ของ Google Maps Platform สำหรับ Android ซึ่งจะช่วยให้คุณใช้ประโยชน์จากฟีเจอร์ต่างๆ ของภาษา Kotlin ได้ เช่น ฟังก์ชันส่วนขยาย พารามิเตอร์ที่มีชื่อและอาร์กิวเมนต์เริ่มต้น การประกาศแบบแยกโครงสร้าง และโคโริวทีน สำหรับข้อมูลเพิ่มเติม โปรดดูหัวข้อต่อไปนี้

Play Core KTX

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

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

GroovyKotlin
dependencies {
    implementation "com.google.android.play:core-ktx:1.8.1"
}
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