Android KTX חלק מ-Android Jetpack.

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

  • פונקציות של תוספים
  • מאפייני תוסף
  • למבדאס
  • פרמטרים בעלי שם
  • ערכי ברירת מחדל של פרמטרים
  • קורוטינים

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

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

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

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

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

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

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

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

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

מגניב

repositories {
    google()
}

Kotlin

repositories {
    google()
}

מודולים של AndroidX

Android KTX מסודר במודולים, כאשר כל מודול מכיל אחד או יותר חבילות.

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

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

פרט למודול הליבה, כל ארטיפקטים של מודול 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:

אוסף KTX

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

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

מגניב

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

Kotlin

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

תוספי קולקציות מנצלים את עומס יתר של מפעיל של 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 KTX מספק כמה תוספים כדי לפשט את ה-API למקטעים.

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

מגניב

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

Kotlin

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

עם מודול Fragment KTX אפשר לפשט עסקאות עם מקטעים עם lambdas, לדוגמה:

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

KTX של מחזור חיים

בשיטה KTX מחזור החיים מוגדר LifecycleScope לכל אובייקט Lifecycle. כל קורוטין שהופעל בהיקף הזה מבוטל כשה-Lifecycle מושמד. אפשר לגשת אל CoroutineScope של Lifecycle באמצעות lifecycle.coroutineScope או lifecycleOwner.lifecycleScope.

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

מגניב

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

Kotlin

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

הדוגמה הבאה ממחישה איך להשתמש ב-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 של האפליקציה:

מגניב

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

Kotlin

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

בדוגמה הבאה, 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-idiomatic.

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

מגניב

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

Kotlin

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

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

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

מודול KTX של Palette מציעה תמיכה אידיומטית ב-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]

KTX של סטרימינג תגובתי

מודול KTX של Reactive Streams מאפשר ליצור זרם LiveData גלוי מ- בעל אפליקציה ב-ReactiveStreams.

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

מגניב

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

Kotlin

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

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

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

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

מגניב

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

Kotlin

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

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

כדי להשתמש במודול הזה, צריך להוסיף את הקוד הבא לקובץ 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 של האפליקציה:

מגניב

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

Kotlin

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

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

כדי לכלול את המודול הזה, יש להוסיף את הקוד הבא לקובץ 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 KTX

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

הפעלה של Core KTX

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

כדי לכלול את המודול הזה, יש להוסיף את הקוד הבא לקובץ 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