Android KTX   חלק מ-Android Jetpack.

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

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

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

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

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

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

מבצע הקריאה יכול לבחור אם לשמור או להחיל את השינויים. פונקציית lambda‏ action היא בעצמה פונקציית תוסף אנונימית ב-SharedPreferences.Editor שמחזירה את הערך Unit, כפי שמצוין בחתימתה. לכן, בתוך הבלוק אפשר לבצע את העבודה ישירות ב-SharedPreferences.Editor.

לבסוף, החתימה SharedPreferences.edit() מכילה את מילת המפתח inline. מילת המפתח הזו מורה למהדר של Kotlin להעתיק ולהדביק (או להטמיע) את הקוד הבינארי המהדר של הפונקציה בכל פעם שמשתמשים בפונקציה. כך אפשר למנוע את העלויות הנלוות של יצירת מופע חדש של כל action בכל פעם שמפעילים את הפונקציה הזו.

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

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

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

Groovy

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

מגניב

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

Kotlin

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

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

Collection KTX

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

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

Groovy

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

Kotlin

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

התוספים של האוספים מנצלים את עומס היתר של האופרטורים ב-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

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

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

מגניב

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

Kotlin

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

בעזרת מודול Fragment KTX אפשר לפשט טרנזקציות של קטעים באמצעות פונקציות lambda, לדוגמה:

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. כל רצף משימות מרובות (coroutine) שמופעל בהיקף הזה מבוטל כשה-Lifecycle נהרס. אפשר לגשת ל-CoroutineScope של ה-Lifecycle באמצעות המאפיינים lifecycle.coroutineScope או lifecycleOwner.lifecycleScope.

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

מגניב

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

Kotlin

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

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

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

מגניב

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

Kotlin

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

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

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

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

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

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

מגניב

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

Kotlin

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

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

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 swatch עבור target נתון באמצעות אופרטור get‏ ([ ]):

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

Reactive Streams KTX

מודול KTX של Reactive Streams מאפשר ליצור מקור ReactiveStreams של שידור LiveData שניתן לצפות בו.

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

מגניב

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

Kotlin

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

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

Room KTX

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

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

מגניב

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

Kotlin

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

ריכזנו כאן כמה דוגמאות שבהן Room משתמש עכשיו ב-coroutines. בדוגמה הראשונה נעשה שימוש בפונקציה 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 של האפליקציה:

מגניב

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

Kotlin

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

דוגמה לשימוש בתוסף 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.8.5"
}

Kotlin

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

לדוגמה, הפונקציה 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.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 זמין במאמר שימוש בשרשור ב-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

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

Google Maps Platform KTX

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

Play Core KTX

Play Core KTX מוסיף תמיכה ב-coroutines של 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.