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

מה חדש בגרסת 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 layout 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:

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

Happy Composing

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

נכתב על ידי:

להמשך הקריאה