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 מספק תוספים לספריות נפוצות שהן חלק מ-framework של 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

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

}

פלטת 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)
}

חדר 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 בטרנזקציות, וכך לא משתמשים הרבה בקודים (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
}

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 תוכלו לעיין במאמר Threading ב-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.