‫Android KTX   בארגז הכלים Android Jetpack.

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

  • פונקציות של תוספים
  • מאפייני התוסף
  • פונקציות Lambda
  • פרמטרים בעלי שם
  • ערכי ברירת המחדל של הפרמטרים
  • שגרות המשך (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.19.1"
}

Kotlin

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

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

KTX של אוסף

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

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

Groovy

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

Kotlin

dependencies {
    implementation("androidx.collection:collection-ktx:1.6.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 מספק כמה תוספים שמפשטים את ה-API של Fragment.

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

מגניב

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

Kotlin

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

בעזרת המודול 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.11.0"
}

Kotlin

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

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

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

Groovy

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

Kotlin

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

בדוגמה הבאה, loadUser() היא פונקציית השהיה שהוגדרה במקום אחר. אפשר להשתמש בפונקציית ה-builder‏ liveData כדי להפעיל את loadUser() באופן אסינכרוני, ואז להשתמש ב-emit() כדי להפיק את התוצאה:

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

מידע נוסף על שימוש בשגרות המשך עם LiveData זמין במאמר שימוש בשגרות המשך ב-Kotlin עם רכיבי ארכיטקטורה.

לכל רכיב בספריית Navigation יש גרסת KTX משלו, שמתאימה את ה-API כך שיהיה תמציתי יותר ואידיומטי ל-Kotlin.

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

Groovy

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

Kotlin

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

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

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

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

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

Groovy

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

Kotlin

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

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

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

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

Room KTX

תוספי Room מוסיפים תמיכה ב-coroutine לעסקאות במסד הנתונים.

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

מגניב

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

Kotlin

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

הנה כמה דוגמאות למקרים שבהם 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 של האפליקציה:

Groovy

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

Kotlin

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

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

db.transaction {
    // insert data
}

ViewModel KTX

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

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

Groovy

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

Kotlin

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

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

WorkManager KTX

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

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

Groovy

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

Kotlin

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

במקום להרחיב את 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 כדי להשהות את ה-coroutine הנוכחי.

בדוגמה הבאה מושהה ה-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

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

‫KTX של Google Maps Platform

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

Play Core KTX

ספריית Play Core KTX מוסיפה תמיכה בקורוטינות של Kotlin לבקשות חד-פעמיות ול-Flow למעקב אחרי עדכוני סטטוס, על ידי הוספת פונקציות של תוספים ל-SplitInstallManager ול-AppUpdateManager בספריית Play Core.

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

Groovy

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.