חדשות על מוצרים

מה חדש בגרסת Jetpack פיתוח נייטיב מדצמבר 2025

משך הקריאה: 6 דקות
Nick Butcher
ניהול מוצרים

היום, הגרסה של Jetpack פיתוח נייטיב מדצמבר 2025 יציבה. הגרסה הזו כוללת את גרסה 1.10 של מודולי הליבה של Compose ואת גרסה 1.4 של Material 3 (אפשר לעיין במיפוי המלא של BOM), ונוספו בה תכונות חדשות ושיפורים משמעותיים בביצועים.

כדי להשתמש בגרסה של היום, צריך לשדרג את גרסת ה-BOM של Compose ל-2025.12.00:

implementation(platform("androidx.compose:compose-bom:2025.12.00"))

שיפורים בביצועים

אנחנו יודעים שביצועי זמן הריצה של האפליקציה חשובים מאוד לך ולמשתמשים שלך, ולכן הביצועים היו בראש סדר העדיפויות של צוות Compose. הגרסה הזו כוללת מספר שיפורים – כדי ליהנות מכולם, פשוט משדרגים לגרסה העדכנית ביותר. השוואות הביצועים הפנימיות שלנו מראות שהביצועים של Compose זהים לביצועים שהיו מתקבלים אם הייתם משתמשים ב-Views:

janky.png

השוואת ביצועי גלילה של Views ו-Jetpack פיתוח נייטיב בגרסאות שונות של פיתוח נייטיב

קומפוזיציה שניתן להשהות בטעינה מראש עצלה

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

בעבר, אחרי שהתחלתם ליצור מוזיקה, הייתם צריכים לחכות עד שהיצירה תסתיים. אם הקומפוזיציה מורכבת, היא עלולה לחסום את ה-thread הראשי למשך זמן ארוך יותר מפריים אחד, ולגרום לממשק המשתמש לקפוא. עם ההרכבה שניתנת להשהיה, סביבת זמן הריצה יכולה עכשיו 'להשהות' את העבודה שלה אם היא מתקרבת לסיום הזמן, ולחדש את העבודה בפריים הבא. השיטה הזו יעילה במיוחד כשמשתמשים בה עם טעינה מראש של פריסת לייאאוט כדי להכין מסגרות מראש. ממשקי ה-API של פריסת Lazy CacheWindow שהוצגו ב-Compose 1.9 הם דרך מצוינת לאחזר מראש יותר תוכן וליהנות מהרכבה שניתנת להשהיה כדי ליצור ביצועים חלקים יותר בממשק המשתמש.

pausable.gif

השילוב של קומפוזיציה שניתן להשהות עם אחזור מראש עצלן עוזר לצמצם את הבעיה של קפיצות בתמונה

בנוסף, שיפרנו את הביצועים במקומות אחרים, כולל Modifier.onPlaced, Modifier.onVisibilityChanged ויישומים אחרים של משנים. נמשיך להשקיע בשיפור הביצועים של התכונה 'כתיבה בעזרת AI'.

תכונות חדשות

שימור

ב-Compose יש מספר ממשקי API לשמירה ולניהול של מצב במחזורי חיים שונים. לדוגמה, remember שומר את המצב בין קומפוזיציות, ו-rememberSavable/rememberSerializable שומר את המצב בין פעילויות או בין יצירה מחדש של תהליכים. ‫retain הוא API חדש שפועל בין ממשקי ה-API האלה, ומאפשר לכם לשמור ערכים לאורך שינויים בהגדרות בלי לבצע סריאליזציה, אבל לא לאורך סיום תהליך. ‫retain לא מבצע סריאליזציה של המצב, ולכן אפשר לשמור אובייקטים כמו ביטויי למדה, זרימות ואובייקטים גדולים כמו מפות סיביות, שלא ניתן לבצע להם סריאליזציה בקלות. לדוגמה, אפשר להשתמש ב- retain כדי לנהל נגן מדיה (כמו ExoPlayer) ולוודא שהפעלת המדיה לא תופרע בגלל שינוי בהגדרה.

@Composable

fun MediaPlayer() {

    val applicationContext = LocalContext.current.applicationContext

    val exoPlayer = retain { ExoPlayer.Builder(applicationContext).apply { ... }.build() }

    ...

}

אנחנו רוצים להודות לקהילת AndroidDev (במיוחד לצוות Circuit) על ההשפעה והתרומה שלהם לעיצוב התכונה הזו.

חומר 1.4

בגרסה 1.4.0 של הספרייה material3 הוספנו מספר רכיבים חדשים ושיפורים:

centered-hero-carousel.webp

קרוסלת תמונות אופקית במרכז

הערה: ממשקי ה-API של Material 3 Expressive ממשיכים להתפתח בגרסאות האלפא של ספריית material3. מידע נוסף זמין בהרצאה הבאה:

תכונות חדשות שקשורות לאנימציות

אנחנו ממשיכים להרחיב את ממשקי ה-API של האנימציות, כולל עדכונים להתאמה אישית של אנימציות של רכיבים משותפים.

רכיבים דינמיים משותפים

כברירת מחדל, האנימציות של sharedElement() ושל sharedBounds() מנסות להנפיש

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

כדי לקבוע אם מעבר הרכיב המשותף יתרחש, אתם יכולים עכשיו להתאים אישית את SharedContentConfig שמועבר אל rememberSharedContentState(). המאפיין isEnabled קובע אם הרכיב המשותף פעיל.

SharedTransitionLayout {

        val transition = updateTransition(currentState)

        transition.AnimatedContent { targetState ->

            // Create the configuration that depends on state changing.

            fun animationConfig() : SharedTransitionScope.SharedContentConfig {

                return object : SharedTransitionScope.SharedContentConfig {

                    override val SharedTransitionScope.SharedContentState.isEnabled: Boolean

                        get() =

                            // determine whether to perform a shared element transition

                }

            }

}

מידע נוסף זמין במאמרי העזרה.

Modifier.skipToLookaheadPosition()

בגרסה הזו נוסף משנה חדש, Modifier.skipToLookaheadPosition(), ששומר על המיקום הסופי של רכיב שאפשר להרכיב כשמבצעים אנימציות של רכיבים משותפים. כך אפשר לבצע מעברים כמו אנימציה מסוג 'חשיפה', כפי שאפשר לראות בדוגמה של Androidify עם החשיפה ההדרגתית של המצלמה. מידע נוסף זמין בסרטון הבא: 

מהירות התחלתית במעברים של רכיבים משותפים

בגרסה הזו הוספנו API חדש למעבר בין רכיבים משותפים, prepareTransitionWithInitialVelocity, שמאפשר להעביר מהירות התחלתית (למשל ממחוות) למעבר בין רכיבים משותפים:

Modifier.fillMaxSize()

    .draggable2D(

        rememberDraggable2DState { offset += it },

        onDragStopped = { velocity ->

            // Set up the initial velocity for the upcoming shared element

            // transition.

            sharedContentStateForDraggableCat

                ?.prepareTransitionWithInitialVelocity(velocity)

            showDetails = false

        },

    )
fling-shared.gif

מעבר בין רכיבים משותפים שמתחיל במהירות התחלתית ממחוות

מעברים מוסתרים

הפונקציות EnterTransition ו-ExitTransition מגדירות איך הקומפוזבל AnimatedVisibility/AnimatedContent מופיע או נעלם. אפשרות ניסיונית חדשה מאפשרת לציין צבע להסתרת תוכן; למשל, הוספה והסרה של שכבה שחורה חצי אטומה מעל תוכן:

veil_2.gif

תוכן אנימציה מוסתר – שימו לב לווילון (או למסך) החצי אטום מעל תוכן הרשת במהלך האנימציה

AnimatedContent(

    targetState = page,

    modifier = Modifier.fillMaxSize().weight(1f),

    transitionSpec = {

        if (targetState > initialState) {

            (slideInHorizontally { it } togetherWith

                    slideOutHorizontally { -it / 2 } + veilOut(targetColor = veilColor))

        } else {

            slideInHorizontally { -it / 2 } +

                    unveilIn(initialColor = veilColor) togetherWith slideOutHorizontally { it }

        }

    },

) { targetPage ->

    ...

}

שינויים קרובים

הוצאה משימוש של Modifier.onFirstVisible

ב-Compose 1.9 נוספו Modifier.onVisibilityChanged ו-Modifier.onFirstVisible. אחרי שבדקנו את המשוב שלך, התברר שלא ניתן לכבד את החוזה של Modifier.onFirstVisible באופן דטרמיניסטי, במיוחד כשפריט first הופך לגלוי. לדוגמה, פריסה מסוג Lazy עשויה להסיר פריטים שגוללים מחוץ לאזור התצוגה, ואז להוסיף אותם מחדש אם הם גוללים חזרה לתצוגה. במקרה כזה, ההתקשרות חזרה onFirstVisible תופעל שוב, כי מדובר בפריט חדש. התנהגות דומה תתרחש גם כשחוזרים למסך שבו ביקרתם קודם ומכיל onFirstVisible. לכן החלטנו להוציא משימוש את שינוי ההתנהגות הזה בגרסת Compose הבאה (1.11) ולעודד מעבר אל onVisibilityChanged. מידע נוסף זמין במאמרי העזרה.

הפעלת שגרות המשך (coroutine) בבדיקות

אנחנו מתכננים לשנות את השליחה של שגרות המשך (coroutine) בבדיקות כדי לשפר את היציבות של הבדיקות ולזהות יותר בעיות. בשלב הזה, הבדיקות משתמשות ב-UnconfinedTestDispatcher, ששונה מההתנהגות בסביבת הייצור. לדוגמה, אפקטים עשויים לפעול באופן מיידי במקום להתווסף לתור. בגרסה עתידית, אנחנו מתכננים להשיק API חדש שמשתמש ב-StandardTestDispatcher כברירת מחדל כדי להתאים להתנהגויות של סביבת הייצור. אתם יכולים לנסות את ההתנהגות החדשה עכשיו בגרסה 1.10:

@get:Rule // also createAndroidComposeRule, createEmptyComposeRule

val rule = createComposeRule(effectContext = StandardTestDispatcher())

השימוש ב-StandardTestDispatcher יוצר תור של משימות, ולכן צריך להשתמש במנגנוני סנכרון כמו composeTestRule.waitForIdle() או composeTestRule.runOnIdle(). אם הבדיקה שלכם משתמשת ב-runTest, אתם צריכים לוודא שמופע runTest וכלל הכתיבה שלכם משתפים את אותו מופע StandardTestDispatcher לצורך סנכרון.

// 1. Create a SINGLE dispatcher instance

val testDispatcher = StandardTestDispatcher()



// 2. Pass it to your Compose rule

@get:Rule

val composeRule = createComposeRule(effectContext = testDispatcher)



@Test

// 3. Pass the *SAME INSTANCE* to runTest

fun myTest() = runTest(testDispatcher) {

    composeRule.setContent { /* ... */ }

}

כלים

ממשקי API מעולים ראויים לכלים מעולים, וב-Android Studio יש כמה תוספות חדשות למפתחי Compose:

כדי לראות את הכלים האלה בפעולה, אפשר לצפות בהדגמה הזו:

כתיבה מהנה

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

נכתב על ידי:

להמשך הקריאה