प्रॉडक्ट से जुड़ी खबरें

Jetpack Compose के दिसंबर '25 वर्शन में नया क्या है

पढ़ने में 6 मिनट लगेंगे
निक बुचर की प्रोफ़ाइल देखें
Nick Butcher प्रॉडक्ट मैनेजर

आज, Jetpack Compose का दिसंबर '25 वर्शन अब स्टेबल है. इसमें Compose के मुख्य मॉड्यूल का वर्शन 1.10 और मटीरियल 3 का वर्शन 1.4 शामिल है. पूरी बीओएम मैपिंग देखें. इसमें नई सुविधाएं जोड़ी गई हैं और परफ़ॉर्मेंस में काफ़ी सुधार किया गया है.

आज के वर्शन का इस्तेमाल करने के लिए, अपने Compose बीओएम वर्शन को 2025.12.00 पर अपग्रेड करें:

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

परफ़ॉर्मेंस में सुधार

हम जानते हैं कि आपके और आपके उपयोगकर्ताओं के लिए, आपके ऐप्लिकेशन की रनटाइम परफ़ॉर्मेंस बहुत अहम है. इसलिए, Compose टीम ने परफ़ॉर्मेंस को अपनी सबसे बड़ी प्राथमिकता दी है. इस वर्शन में कई सुधार किए गए हैं. इन्हें पाने के लिए, आपको सिर्फ़ नए वर्शन पर अपग्रेड करना होगा. स्क्रोल करने की परफ़ॉर्मेंस के हमारे इंटरनल बेंचमार्क से पता चलता है कि Compose अब Views के इस्तेमाल से मिलने वाली परफ़ॉर्मेंस के बराबर है:

janky.png

स्क्रोल करने की परफ़ॉर्मेंस का बेंचमार्क. इसमें Compose के अलग-अलग वर्शन में Views और Jetpack Compose की तुलना की गई है

लेज़ी प्रीफ़ेच में पॉज़ किया जा सकने वाला कंपोज़िशन

लेज़ी प्रीफ़ेच में पॉज़ किया जा सकने वाला कंपोज़िशन अब डिफ़ॉल्ट रूप से चालू है. यह Compose रनटाइम के शेड्यूल के काम करने के तरीके में एक बुनियादी बदलाव है. इसे यूज़र इंटरफ़ेस (यूआई) के ज़्यादा लोड वाले कामों के दौरान, जंक को काफ़ी कम करने के लिए डिज़ाइन किया गया है.

पहले, कंपोज़िशन शुरू होने के बाद, उसे पूरा करना पड़ता था. अगर कोई कंपोज़िशन जटिल था, तो इससे मुख्य थ्रेड एक फ़्रेम से ज़्यादा समय के लिए ब्लॉक हो सकता था. इससे यूज़र इंटरफ़ेस (यूआई) फ़्रीज़ हो जाता था. पॉज़ किए जा सकने वाले कंपोज़िशन की मदद से, रनटाइम अब अपना काम "पॉज़" कर सकता है. ऐसा तब किया जा सकता है, जब उसके पास समय कम हो. इसके बाद, वह अगले फ़्रेम में काम फिर से शुरू कर सकता है. यह खास तौर पर तब काम आता है, जब इसका इस्तेमाल लेज़ी लेआउट प्रीफ़ेच के साथ किया जाता है, ताकि फ़्रेम को पहले से तैयार किया जा सके. Compose 1.9 में लॉन्च किए गए, Lazy layout CacheWindow API की मदद से ज़्यादा कॉन्टेंट को प्रीफ़ेच किया जा सकता है. साथ ही, पॉज़ किए जा सकने वाले कंपोज़िशन का फ़ायदा लिया जा सकता है, ताकि यूज़र इंटरफ़ेस (यूआई) की परफ़ॉर्मेंस को बेहतर बनाया जा सके.

pausable.gif

लेज़ी प्रीफ़ेच के साथ पॉज़ किए जा सकने वाले कंपोज़िशन की मदद से, जंक को कम किया जा सकता है

हमने अन्य जगहों पर भी परफ़ॉर्मेंस को ऑप्टिमाइज़ किया है. जैसे, Modifier.onPlacedModifier.onVisibilityChanged, और अन्य मॉडिफ़ायर लागू करने में सुधार किया गया है. हम Compose की परफ़ॉर्मेंस को बेहतर बनाने के लिए लगातार काम करते रहेंगे.

नई सुविधाएं

Retain

Compose, अलग-अलग लाइफ़साइकल में स्टेट को बनाए रखने और मैनेज करने के लिए कई एपीआई उपलब्ध कराता है. उदाहरण के लिए, remember कंपोज़िशन के बीच स्टेट को बनाए रखता है. वहीं, rememberSavable/rememberSerializable गतिविधि या प्रोसेस को फिर से बनाने के दौरान स्टेट को बनाए रखता है.retain एक नया एपीआई है, जो इन एपीआई के बीच काम करता है. इसकी मदद से, कॉन्फ़िगरेशन में बदलाव होने पर भी वैल्यू को बनाए रखा जा सकता है. हालांकि, प्रोसेस बंद होने पर वैल्यू को बनाए नहीं रखा जा सकता. retain आपकी स्टेट को क्रम से नहीं लगाता. इसलिए, लैम्डा एक्सप्रेशन, फ़्लो, और बिटमैप जैसे बड़े ऑब्जेक्ट को बनाए रखा जा सकता है. इन्हें आसानी से क्रम से नहीं लगाया जा सकता. उदाहरण के लिए, मीडिया प्लेयर (जैसे, ExoPlayer) को मैनेज करने के लिए, retain का इस्तेमाल किया जा सकता है. इससे यह पक्का किया जा सकता है कि कॉन्फ़िगरेशन में बदलाव होने पर, मीडिया प्लेबैक में कोई रुकावट न आए.

@Composable

fun MediaPlayer() {

    val applicationContext = LocalContext.current.applicationContext

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

    ...

}

हम AndroidDev कम्यूनिटी (खास तौर पर, Circuit टीम) का शुक्रिया अदा करना चाहते हैं. इस टीम ने इस सुविधा के डिज़ाइन को बेहतर बनाने में अहम योगदान दिया है.

मटीरियल 1.4

material3 लाइब्रेरी के वर्शन 1.4.0 में, कई नए कॉम्पोनेंट और बेहतर सुविधाएं जोड़ी गई हैं:

  • TextField अब एक एक्सपेरिमेंटल TextFieldState पर आधारित वर्शन उपलब्ध कराता है. इससे टेक्स्ट की स्टेट को मैनेज करने का ज़्यादा बेहतर तरीका मिलता है. इसके अलावा, नए SecureTextField और OutlinedSecureTextField वैरिएंट अब उपलब्ध हैं. मटीरियल Text कंपोज़ेबल अब autoSize के व्यवहार के साथ काम करता है.
  • कैरसेल कॉम्पोनेंट अब HorizontalCenteredHeroCarousel वैरिएंट का नया उपलब्ध कराता है.
  • TimePicker अब पिकर और इनपुट मोड के बीच स्विच करने की सुविधा देता है.
  • एक वर्टिकल ड्रैग हैंडल की मदद से, उपयोगकर्ता अडैप्टिव पैनल का साइज़ और/या उसकी जगह बदल सकते हैं.
centered-hero-carousel.webp

हॉरिज़ॉन्टल सेंटर्ड हीरो कैरसेल

ध्यान दें कि मटीरियल 3 के शानदार एपीआई को material3 लाइब्रेरी के अल्फ़ा वर्शन में डेवलप किया जा रहा है. ज़्यादा जानने के लिए, हाल ही में हुई इस बातचीत को देखें:

ऐनिमेशन की नई सुविधाएं

हम अपने ऐनिमेशन एपीआई को बेहतर बनाने के लिए लगातार काम कर रहे हैं. इसमें, शेयर किए गए एलिमेंट के ऐनिमेशन को पसंद के मुताबिक बनाने के लिए अपडेट शामिल हैं.

डाइनैमिक शेयर किए गए एलिमेंट

डिफ़ॉल्ट रूप से, sharedElement() और sharedBounds() ऐनिमेशन, इन चीज़ों को ऐनिमेट करने की कोशिश करते हैं

लेआउट में बदलाव, जब भी टारगेट स्टेट में मैचिंग की मिलती है. हालांकि, कुछ शर्तों के आधार पर, इस ऐनिमेशन को डाइनैमिक तरीके से बंद किया जा सकता है. जैसे, नेविगेशन की दिशा या मौजूदा यूज़र इंटरफ़ेस (यूआई) की स्टेट.

शेयर किए गए एलिमेंट का ट्रांज़िशन होगा या नहीं, यह कंट्रोल करने के लिए, अब rememberSharedContentState() को पास किए गए SharedContentConfig को पसंद के मुताबिक बनाया जा सकता है. 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 के सैंपल में, कैमरे के प्रोग्रेसिव रीवील के साथ देखा जा सकता है. ज़्यादा जानकारी के लिए, यहां वीडियो टिप देखें: 

शेयर किए गए एलिमेंट के ट्रांज़िशन में शुरुआती वेलोसिटी

इस वर्शन में, शेयर किए गए एलिमेंट के ट्रांज़िशन का नया एपीआई, 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 के कॉन्ट्रैक्ट को तय तरीके से पूरा नहीं किया जा सकता. खास तौर पर, जब कोई आइटम पहली बार दिखता है. उदाहरण के लिए, लेज़ी लेआउट उन आइटम को हटा सकता है जो व्यूपोर्ट से बाहर स्क्रोल हो जाते हैं. इसके बाद, अगर वे वापस व्यू में स्क्रोल होते हैं, तो उन्हें फिर से कंपोज़ किया जा सकता है. इस स्थिति में, onFirstVisible कॉलबैक फिर से ट्रिगर होगा, क्योंकि यह एक नया कंपोज़ किया गया आइटम है. इसी तरह का व्यवहार, पहले देखी गई उस स्क्रीन पर वापस जाने पर भी होगा जिसमें onFirstVisible शामिल है. इसलिए, हमने Compose के अगले वर्शन (1.11) में इस मॉडिफ़ायर को बंद करने का फ़ैसला किया है. हमारा सुझाव है कि onVisibilityChanged पर माइग्रेट करें. ज़्यादा जानकारी के लिए, दस्तावेज़ देखें.

टेस्ट में कोरूटीन डिस्पैच

हम टेस्ट में कोरूटीन डिस्पैच में बदलाव करने की योजना बना रहे हैं, ताकि टेस्ट में गड़बड़ी की संभावना को कम किया जा सके और ज़्यादा समस्याओं को पकड़ा जा सके. फ़िलहाल, टेस्ट में UnconfinedTestDispatcher का इस्तेमाल किया जाता है.यह प्रोडक्शन के व्यवहार से अलग है. उदाहरण के लिए, इफ़ेक्ट को एनक्वीव करने के बजाय, तुरंत चलाया जा सकता है. हम आने वाले समय में एक नया एपीआई लॉन्च करने की योजना बना रहे हैं. इसमें प्रोडक्शन के व्यवहार से मैच करने के लिए, डिफ़ॉल्ट रूप से StandardTestDispatcher का इस्तेमाल किया जाएगा. 1.10 में अभी नया व्यवहार आज़माया जा सकता है:

@get:Rule // also createAndroidComposeRule, createEmptyComposeRule

val rule = createComposeRule(effectContext = StandardTestDispatcher())

StandardTestDispatcher का इस्तेमाल करने पर, टास्क को क्यू में रखा जाएगा. इसलिए, आपको composeTestRule.waitForIdle() या composeTestRule.runOnIdle() जैसे सिंक्रनाइज़ेशन मैकेनिज़्म का इस्तेमाल करना होगा. अगर आपके टेस्ट में runTest का इस्तेमाल किया जाता है, तो आपको यह पक्का करना होगा कि सिंक्रनाइज़ेशन के लिए, runTest और आपके Compose नियम, 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 { /* ... */ }

}

टूल

बेहतरीन एपीआई के लिए बेहतरीन टूल ज़रूरी हैं. Android Studio में, Compose डेवलपर के लिए हाल ही में कई टूल जोड़े गए हैं:

इन टूल को ऐक्शन में देखने के लिए, हाल ही में किया गया यह डेमो देखें:

Compose का इस्तेमाल करके शानदार यूज़र इंटरफ़ेस (यूआई) बनाएं

हम Jetpack Compose को बेहतर बनाने के लिए लगातार काम कर रहे हैं, ताकि आपको शानदार और बेहतर यूज़र इंटरफ़ेस (यूआई) बनाने के लिए ज़रूरी एपीआई और टूल उपलब्ध कराए जा सकें. हम आपके सुझावों को अहमियत देते हैं. इसलिए, कृपया इन बदलावों के बारे में अपनी राय या सुझाव दें. इसके अलावा, हमें यह भी बताएं कि आपको हमारे इश्यू ट्रैकर में आगे क्या देखना है.

लेखक:
पढ़ना जारी रखें