‫Android KTX   חלק מ-Android Jetpack.

‫Android KTX היא קבוצה של תוספי Kotlin שנכללים ב-Android Jetpack ובספריות אחרות של Android. תוספי KTX מספקים קוד Kotlin תמציתי, אידיומטי ל-Jetpack, לפלטפורמת Android ולממשקי API אחרים. לשם כך, התוספים האלה מסתמכים על כמה תכונות של שפת Kotlin, כולל התכונות הבאות:

  • פונקציות של תוספים
  • מאפייני התוסף
  • Lambdas
  • פרמטרים עם שם
  • ערכי ברירת מחדל של פרמטרים
  • שגרות משנה (coroutines)

לדוגמה, כשעובדים עם SharedPreferences, צריך ליצור הרשאת עריכה לפני שאפשר לבצע שינויים בנתוני ההעדפות. בסיום העריכה, צריך גם להחיל או לאשר את השינויים, כמו בדוגמה הבאה:

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

ביטויים מסוג Lambda ב-Kotlin מתאימים מאוד לתרחיש השימוש הזה. הם מאפשרים לכם להשתמש בגישה תמציתית יותר על ידי העברת בלוק קוד לביצוע אחרי יצירת העורך, ביצוע הקוד ואז מתן אפשרות ל-API של SharedPreferences להחיל את השינויים באופן אטומי.

דוגמה לאחת מהפונקציות של Android KTX Core, SharedPreferences.edit, שמוסיפה פונקציית עריכה ל-SharedPreferences. הפונקציה הזו מקבלת דגל 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 שהוא צריך להעתיק ולהדביק (או להטמיע) את בייטקוד המהדר של הפונקציה בכל פעם שמשתמשים בפונקציה. כך נמנעים מהתקורה של יצירת מופע חדש של מחלקה לכל action בכל פעם שהפונקציה הזו מופעלת.

הדפוס הזה של העברת קוד באמצעות ביטויי למדה, החלת ברירות מחדל הגיוניות שאפשר לבטל והוספת ההתנהגויות האלה לממשקי API קיימים באמצעות inlineפונקציות הרחבה, הוא אופייני לשיפורים שמסופקים על ידי ספריית Android KTX.

שימוש ב-Android KTX בפרויקט

כדי להתחיל להשתמש ב-Android KTX, מוסיפים את התלות הבאה לקובץ build.gradle של הפרויקט:

מגניב

repositories {
    google()
}

Kotlin

repositories {
    google()
}

מודולים של AndroidX

‫Android KTX מאורגן במודולים, וכל מודול מכיל חבילה אחת או יותר.

צריך לכלול תלות בכל ארטיפקט של מודול בקובץ build.gradle של האפליקציה. חשוב לזכור להוסיף את מספר הגרסה לארטיפקט. מספרי הגרסאות העדכניים מופיעים בקטע המתאים לכל ארטיפקט בנושא הזה.

‫Android KTX מכיל מודול ליבה יחיד שמספק תוספים של Kotlin לממשקי API נפוצים של מסגרות ולכמה תוספים ספציפיים לתחום.

חוץ מהארטיפקטים של מודול הליבה, כל הארטיפקטים של מודול KTX מחליפים את התלות הבסיסית ב-Java בקובץ build.gradle. לדוגמה, אפשר להחליף תלות androidx.fragment:fragment ב-androidx.fragment:fragment-ktx. התחביר הזה עוזר לנהל טוב יותר את הגרסאות ולא מוסיף דרישות נוספות להצהרת תלות.

Core KTX

מודול ה-Core KTX מספק תוספים לספריות נפוצות שמהוות חלק ממסגרת Android. לספריות האלה אין תלויות מבוססות-Java שצריך להוסיף ל-build.gradle.

כדי לכלול את המודול הזה, מוסיפים את השורות הבאות לקובץ build.gradle של האפליקציה:

Groovy

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

Kotlin

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

זו רשימה של החבילות שנכללות במודול Core KTX:

Collection KTX

תוספי האוסף מכילים פונקציות עזר לעבודה עם ספריות אוסף חסכוניות בזיכרון של Android, כולל ArrayMap,‏ LongSparseArray,‏ LruCache ועוד.

כדי להשתמש במודול הזה, מוסיפים את השורות הבאות לקובץ build.gradle של האפליקציה:

Groovy

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

Kotlin

dependencies {
    implementation("androidx.collection:collection-ktx:1.5.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

‫Fragment KTX

מודול Fragment KTX מספק מספר תוספים שמפשטים את Fragment API.

כדי לכלול את המודול הזה, מוסיפים את השורות הבאות לקובץ build.gradle של האפליקציה:

מגניב

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

Kotlin

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

בעזרת מודול Fragment 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 של האפליקציה:

Groovy

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

Kotlin

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

בדוגמה הבאה אפשר לראות איך משתמשים ב-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, יכול להיות שיהיה צורך לחשב ערכים באופן אסינכרוני. לדוגמה, יכול להיות שתרצו לאחזר את ההעדפות של משתמש ולהציג אותן בממשק המשתמש שלכם. במקרים כאלה, ספריית LiveData KTX מספקת פונקציית יצירה liveData שקוראת לפונקציה suspend ומציגה את התוצאה כאובייקט LiveData.

כדי לכלול את המודול הזה, מוסיפים את השורות הבאות לקובץ build.gradle של האפליקציה:

Groovy

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

Kotlin

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

בדוגמה הבאה, loadUser() היא פונקציית השהיה שהוגדרה במקום אחר. אפשר להשתמש בפונקציית ה-builder‏ 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 של האפליקציה:

Groovy

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

Kotlin

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

כדי לגשת לארגומנטים של היעד ולעבור ליעדים, משתמשים בפונקציות ההרחבה ובמאפיין delegation, כמו בדוגמה הבאה:

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 של האפליקציה:

מגניב

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]

Reactive Streams KTX

מודול Reactive Streams KTX מאפשר ליצור זרם LiveData ניתן לצפייה מReactiveStreams בעל תוכן דיגיטלי.

כדי לכלול את המודול הזה, מוסיפים את השורות הבאות לקובץ build.gradle של האפליקציה:

Groovy

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

Kotlin

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

לדוגמה, נניח שיש מסד נתונים עם רשימה קטנה של משתמשים. באפליקציה, אתם טוענים את מסד הנתונים לזיכרון ואז מציגים את נתוני המשתמש בממשק המשתמש. כדי לעשות את זה, אפשר להשתמש ב-RxJava. רכיב Jetpack‏ Room יכול לאחזר את רשימת המשתמשים כ-Flowable. בתרחיש הזה, אתם צריכים גם לנהל את המינוי של Rx publisher לאורך כל משך החיים של הפעילות או של הקטע.

עם זאת, בעזרת LiveDataReactiveStreams תוכלו ליהנות מ-RxJava וממערך האופרטורים העשיר שלו, וגם מהיכולות של תזמון עבודה, ועדיין לעבוד עם הפשטות של LiveData, כמו בדוגמה הבאה:

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

‫Room KTX

תוספי Room מוסיפים תמיכה ברוטינות משנה לעסקאות במסד נתונים.

כדי להשתמש במודול הזה, מוסיפים את השורות הבאות לקובץ build.gradle של האפליקציה:

Groovy

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

Kotlin

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

הנה כמה דוגמאות לשימוש בקורוטינות ב-Room: בדוגמה הראשונה נעשה שימוש בפונקציה 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 בעסקאות, וכך מבטלים הרבה קוד boilerplate.

כדי להשתמש במודול הזה, מוסיפים את השורות הבאות לקובץ build.gradle של האפליקציה:

מגניב

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

Kotlin

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

דוגמה לשימוש בתוסף transaction כדי לבצע טרנזקציה במסד נתונים:

db.transaction {
    // insert data
}

ViewModel KTX

ספריית ViewModel KTX מספקת פונקציה viewModelScope() שמקלה על הפעלת coroutines מ-ViewModel. ‫CoroutineScope משויך ל-Dispatchers.Main ומתבטל באופן אוטומטי כשמנקים את ViewModel. אפשר להשתמש ב-viewModelScope() במקום ליצור היקף חדש לכל ViewModel.

כדי לכלול את המודול הזה, מוסיפים את השורות הבאות לקובץ build.gradle של האפליקציה:

Groovy

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

Kotlin

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

לדוגמה, הפונקציה 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()
}

WorkManager KTX

‫WorkManager KTX מספק תמיכה ברמה גבוהה ב-coroutines.

כדי לכלול את המודול הזה, מוסיפים את השורות הבאות לקובץ build.gradle של האפליקציה:

מגניב

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

Kotlin

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

במקום להשתמש ב-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.

Firebase KTX

חלק מ-Firebase SDKs ל-Android כוללים ספריות הרחבה של Kotlin שמאפשרות לכתוב קוד Kotlin אידיומטי כשמשתמשים ב-Firebase באפליקציה. מידע נוסף זמין בנושאים הבאים:

‫Google Maps Platform KTX

יש הרחבות KTX זמינות לערכות SDK של Android בפלטפורמה של מפות Google, שמאפשרות לכם ליהנות מכמה תכונות של שפת Kotlin, כמו פונקציות הרחבה, פרמטרים עם שמות וארגומנטים שמוגדרים כברירת מחדל, הצהרות על פירוק למשתנים וקורוטינות. מידע נוסף זמין בנושאים הבאים:

Play Core KTX

ספריית Play Core KTX מוסיפה תמיכה ב-Kotlin coroutines לבקשות חד-פעמיות וב-Flow למעקב אחרי עדכוני סטטוס, על ידי הוספת פונקציות הרחבה ל-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.