CompositionLocal
कंपोज़िशन के ज़रिए डेटा ट्रांसफ़र कर सकता है. इस पेज पर, आपको
CompositionLocal
के बारे में ज़्यादा जानें और इसे बनाने का तरीका जानें
CompositionLocal
और जानें कि क्या CompositionLocal
एक अच्छा समाधान है
आपके इस्तेमाल का उदाहरण.
पेश है CompositionLocal
आम तौर पर, Compose में, डेटा नीचे की ओर जाता है हर कंपोज़ेबल फ़ंक्शन के पैरामीटर के तौर पर यूआई ट्री. इससे एक कंपोज़ेबल डिपेंडेंसी साफ़ तौर पर दी गई है. हालांकि, यह ऐसे डेटा के लिए बोझिल हो सकता है जो अक्सर और बड़े पैमाने पर इस्तेमाल किए जाते हैं, जैसे कि रंग या टाइप स्टाइल. नीचे दी गई जानकारी देखें उदाहरण:
@Composable fun MyApp() { // Theme information tends to be defined near the root of the application val colors = colors() } // Some composable deep in the hierarchy @Composable fun SomeTextLabel(labelText: String) { Text( text = labelText, color = colors.onPrimary // ← need to access colors here ) }
इसके लिए, रंगों को साफ़ तौर पर पैरामीटर डिपेंडेंसी के तौर पर पास करने की ज़रूरत न हो
Compose CompositionLocal
पर मिलने वाले ऑफ़र से, आपको ज़्यादातर कंपोज़ेबल में
का इस्तेमाल करके ट्री के स्कोप वाले नाम वाले ऑब्जेक्ट बनाए जा सकते हैं. इनका इस्तेमाल करके,
यूज़र इंटरफ़ेस ट्री के ज़रिए डेटा फ़्लो का इस्तेमाल करें.
आम तौर पर, CompositionLocal
एलिमेंट किसी खास नोड में वैल्यू के साथ दिए जाते हैं
पर क्लिक करें. उस वैल्यू का इस्तेमाल, उसके कंपोज़ेबल डिसेंडेंट के बिना किया जा सकता है
कंपोज़ेबल फ़ंक्शन में पैरामीटर के तौर पर CompositionLocal
का एलान करता है.
मटीरियल थीम में CompositionLocal
का इस्तेमाल किया जाता है.
MaterialTheme
है
एक ऑब्जेक्ट जो तीन CompositionLocal
इंस्टेंस——रंग, टाइपोग्राफ़ी, देता है
और आकार—जिससे आप उन्हें बाद में किसी भी वंशज के रूप में
कंपोज़िशन. खास तौर पर, ये हैं LocalColors
, LocalShapes
, और
LocalTypography
प्रॉपर्टी, जिन्हें MaterialTheme
पर जाकर ऐक्सेस किया जा सकता है
colors
, shapes
, और typography
एट्रिब्यूट.
@Composable fun MyApp() { // Provides a Theme whose values are propagated down its `content` MaterialTheme { // New values for colors, typography, and shapes are available // in MaterialTheme's content lambda. // ... content here ... } } // Some composable deep in the hierarchy of MaterialTheme @Composable fun SomeTextLabel(labelText: String) { Text( text = labelText, // `primary` is obtained from MaterialTheme's // LocalColors CompositionLocal color = MaterialTheme.colors.primary ) }
CompositionLocal
इंस्टेंस को कंपोज़िशन के हिस्से में बांटा गया है, ताकि आपको
ट्री के अलग-अलग लेवल पर अलग-अलग वैल्यू दे सकता है. current
वैल्यू
का मान CompositionLocal
कंपोज़िशन के उस हिस्से में पूर्वज.
CompositionLocal
को नई वैल्यू देने के लिए,
CompositionLocalProvider
और इसके provides
इनफ़िक्स फ़ंक्शन का इस्तेमाल करें जो CompositionLocal
कुंजी को value
से जोड़ता है. कॉन्टेंट बनाने
CompositionLocalProvider
में से content
लैम्डा को दिया जाएगा
वैल्यू, CompositionLocal
की current
प्रॉपर्टी को ऐक्सेस करते समय लागू होती है. जब
कोई नई वैल्यू डालने पर, कंपोज़िशन में उस कंपोज़िशन के हिस्से को फिर से शामिल किया जाता है जिस पर क्लिक किया जाता है
CompositionLocal
.
उदाहरण के लिए, LocalContentAlpha
CompositionLocal
में पसंदीदा कॉन्टेंट ऐल्फ़ा शामिल है, जिसका इस्तेमाल टेक्स्ट और
आइकॉनोग्राफ़ी का इस्तेमाल करें. इस
नीचे दिए गए उदाहरण में, CompositionLocalProvider
का इस्तेमाल अलग-अलग
कंपोज़िशन के अलग-अलग हिस्सों की वैल्यू शामिल हैं.
@Composable fun CompositionLocalExample() { MaterialTheme { // MaterialTheme sets ContentAlpha.high as default Column { Text("Uses MaterialTheme's provided alpha") CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) { Text("Medium value provided for LocalContentAlpha") Text("This Text also uses the medium value") CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) { DescendantExample() } } } } } @Composable fun DescendantExample() { // CompositionLocalProviders also work across composable functions Text("This Text uses the disabled alpha now") }
पहला डायग्राम. CompositionLocalExample
कंपोज़ेबल की झलक.
ऊपर दिए गए सभी उदाहरणों में, CompositionLocal
इंस्टेंस का अंदरूनी इस्तेमाल किया गया है
मटीरियल कंपोज़ेबल से. CompositionLocal
की मौजूदा वैल्यू को ऐक्सेस करने के लिए,
इसके current
का इस्तेमाल करें
प्रॉपर्टी. यहां दिए गए उदाहरण में, LocalContext
की मौजूदा Context
वैल्यू
CompositionLocal
को फ़ॉर्मैट करने के लिए आम तौर पर Android ऐप्लिकेशन में इस्तेमाल किया जाता है
लेख:
@Composable fun FruitText(fruitSize: Int) { // Get `resources` from the current value of LocalContext val resources = LocalContext.current.resources val fruitText = remember(resources, fruitSize) { resources.getQuantityString(R.plurals.fruit_title, fruitSize) } Text(text = fruitText) }
अपना CompositionLocal
बनाया जा रहा है
CompositionLocal
एक टूल है, जो कंपोज़िशन के ज़रिए डेटा भेजने के लिए इस्तेमाल किया जाता है
साफ़ तौर पर.
CompositionLocal
का इस्तेमाल करने का दूसरा कुंजी सिग्नल यह है कि पैरामीटर
लागू करने की क्रॉस-कटिंग और इंटरमीडिएट लेयर्स को पता नहीं होना चाहिए
यह मौजूद है, क्योंकि उन इंटरमीडिएट लेयर को जानकारी देने से,
कंपोज़ेबल का इस्तेमाल कर रही हूँ. उदाहरण के लिए, Android की अनुमतियों के लिए क्वेरी करना
CompositionLocal
की ओर से उपलब्ध कराया जाता है. ऐसा मीडिया पिकर जिसे कंपोज़ किया जा सकता है
पर अनुमति से सुरक्षित कॉन्टेंट को ऐक्सेस करने के लिए नई सुविधा जोड़ सकता है:
डिवाइस, अपना एपीआई बदले बिना और मीडिया पिकर के कॉलर को
पर्यावरण से जुड़े इस अतिरिक्त संदर्भ के बारे में जानें.
हालांकि, CompositionLocal
हमेशा सबसे अच्छा समाधान नहीं होता है. बुध
CompositionLocal
के बहुत ज़्यादा इस्तेमाल करने से बचें, क्योंकि इसके कुछ नकारात्मक पहलू हैं:
CompositionLocal
की वजह से किसी कंपोज़ेबल के काम करने के तरीके के बारे में सोच-विचार करना मुश्किल हो जाता है. जैसे
ये इंप्लिसिट डिपेंडेंसी, कंपोज़ेबल के कॉलर बनाते हैं, जिनकी ज़रूरत होती है
ताकि यह पक्का किया जा सके कि हर CompositionLocal
के लिए वैल्यू पूरी हो रही है.
इसके अलावा, यह भी हो सकता है कि इस डिपेंडेंसी के बारे में साफ़ तौर पर कोई जानकारी मौजूद न हो, क्योंकि
कंपोज़िशन के किसी भी हिस्से में बदलाव किया जा सकता है. इसलिए, ऐप्लिकेशन को तब डीबग करें, जब
तो समस्या ज़्यादा बड़ी हो सकती है, क्योंकि
कंपोज़िशन देखकर पता करें कि current
वैल्यू कहां दी गई थी. ढूंढें जैसे टूल
IDE में या लेआउट इंस्पेक्टर लिखें का इस्तेमाल
समस्या को कम करने के लिए किया जा सकता है.
तय करना कि CompositionLocal
का इस्तेमाल करना है या नहीं
कुछ ऐसी शर्तें हैं जो CompositionLocal
को बेहतर समाधान दे सकती हैं
आपके इस्तेमाल के उदाहरण के लिए:
CompositionLocal
की डिफ़ॉल्ट वैल्यू अच्छी होनी चाहिए. अगर कोई डिफ़ॉल्ट सेटिंग सेट न हो
तो आपको इस बात की गारंटी देनी होगी कि डेवलपर के लिए
ऐसी स्थिति में आ जाते हैं, जहां CompositionLocal
के लिए कोई वैल्यू नहीं दी जाती है.
डिफ़ॉल्ट वैल्यू न देने पर, कॉन्टेंट बनाते समय समस्याएं और निराशा हो सकती है
किसी कंपोज़ेबल का टेस्ट करने या उसकी झलक देखने से, जो उस CompositionLocal
का इस्तेमाल करता है
इसे साफ़ तौर पर दिया जाना ज़रूरी है.
ऐसे कॉन्सेप्ट को इस्तेमाल करने के लिए CompositionLocal
का इस्तेमाल न करें जिन्हें पेड़ के स्कोप वाले या
सब-हैरारकी के दायरे में उपलब्ध. CompositionLocal
समझ में आता है कि यह कब होना चाहिए
जिनका इस्तेमाल कुछ ही वंशजों के ज़रिए किया जा सकता है.
अगर इस्तेमाल का आपका उदाहरण इन ज़रूरी शर्तों को पूरा नहीं करता है, तो यहां देखें
सेक्शन बनाने से पहले विचार करने के लिए विकल्प
CompositionLocal
.
गलत तरीके का एक उदाहरण है, ऐसा CompositionLocal
बनाना जो आपके मौजूदा
किसी खास स्क्रीन का ViewModel
, ताकि उस स्क्रीन के सभी कंपोज़ेबल में उपलब्ध
कुछ लॉजिक करने के लिए, ViewModel
का रेफ़रंस पाएं. यह एक खराब तरीका है
क्योंकि किसी खास यूज़र इंटरफ़ेस (यूआई) ट्री के नीचे सभी कंपोज़ेबल को
ViewModel
. सबसे अच्छा तरीका यह है कि कंपोज़ेबल में सिर्फ़ जानकारी दी जाए
उन्हें इस पैटर्न के हिसाब से बनाना होगा कि स्थिति फ़्लो डाउन और इवेंट फ़्लो अप होने पर होती हैं. इस तरीके से, अपने कंपोज़ेबल को ज़्यादा
फिर से इस्तेमाल करने लायक और टेस्ट करने में आसान.
CompositionLocal
बनाया जा रहा है
CompositionLocal
बनाने के लिए दो एपीआई हैं:
compositionLocalOf
: फिर से बनाने के दौरान दिए गए मान को बदलने से सिर्फ़ अमान्य होता है जिसे पढ़ता हैcurrent
वैल्यू.staticCompositionLocalOf
:compositionLocalOf
के उलट,staticCompositionLocalOf
के रीड इसे Compose ने ट्रैक किया है. वैल्यू बदलने सेcontent
पूरी तरह से बदल जाता है Lambda फ़ंक्शन, जहांCompositionLocal
को फिर से लिखने के लिए दिया गया है, न कि सिर्फ़ उन जगहों की जानकारी दें जहां कंपोज़िशन मेंcurrent
वैल्यू पढ़ी गई है.
अगर CompositionLocal
को दी गई वैल्यू में बदलाव होने की संभावना बहुत ज़्यादा है या
कभी नहीं बदलेगा. परफ़ॉर्मेंस के फ़ायदे पाने के लिए, staticCompositionLocalOf
का इस्तेमाल करें.
उदाहरण के लिए, किसी ऐप्लिकेशन के डिज़ाइन सिस्टम की राय, कंपोज़ेबल के हिसाब से दी जा सकती है
यूआई कॉम्पोनेंट के लिए शैडो का इस्तेमाल करके हाइलाइट किए जाते हैं. क्योंकि अलग
यूज़र इंटरफ़ेस (यूआई) ट्री में, ऐप्लिकेशन की एलिवेशन को पूरे यूज़र इंटरफ़ेस (यूआई) ट्री में देखना चाहिए. हम
CompositionLocal
. क्योंकि CompositionLocal
वैल्यू को कंडिशनल तरीके से लिया जाता है
सिस्टम की थीम के हिसाब से, हम compositionLocalOf
एपीआई का इस्तेमाल करते हैं:
// LocalElevations.kt file data class Elevations(val card: Dp = 0.dp, val default: Dp = 0.dp) // Define a CompositionLocal global object with a default // This instance can be accessed by all composables in the app val LocalElevations = compositionLocalOf { Elevations() }
CompositionLocal
के लिए वैल्यू देना
CompositionLocalProvider
कंपोज़ेबल, किसी वैल्यू को CompositionLocal
इंस्टेंस के हिसाब से बाइंड करता है
हैरारकी है. CompositionLocal
को नई वैल्यू देने के लिए,
provides
इनफ़िक्स फ़ंक्शन का इस्तेमाल करें जो CompositionLocal
कुंजी को value
से इस तरह जोड़ता है:
// MyActivity.kt file class MyActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { // Calculate elevations based on the system theme val elevations = if (isSystemInDarkTheme()) { Elevations(card = 1.dp, default = 1.dp) } else { Elevations(card = 0.dp, default = 0.dp) } // Bind elevation as the value for LocalElevations CompositionLocalProvider(LocalElevations provides elevations) { // ... Content goes here ... // This part of Composition will see the `elevations` instance // when accessing LocalElevations.current } } } }
CompositionLocal
का इस्तेमाल करना
CompositionLocal.current
सबसे नज़दीकी CompositionLocalProvider
से मिला वह वैल्यू दिखाता है जो उस CompositionLocal
को कोई वैल्यू देती है:
@Composable fun SomeComposable() { // Access the globally defined LocalElevations variable to get the // current Elevations in this part of the Composition Card(elevation = LocalElevations.current.card) { // Content } }
गौर करने लायक दूसरे विकल्प
इस्तेमाल के कुछ उदाहरणों में, CompositionLocal
की ज़रूरत नहीं पड़ती है. अगर आपके
इस्तेमाल का उदाहरण तय करना कि इस्तेमाल करना है या नहीं
ComposeLocal सेक्शन में कोई दूसरा समाधान बेहतर हो सकता है
आपके इस्तेमाल के हिसाब से सही है.
साफ़ तौर पर जानकारी देने वाले पैरामीटर पास करें
कंपोज़ेबल की डिपेंडेंसी के बारे में साफ़ तौर पर जानकारी देना, एक अच्छी आदत है. हमारा सुझाव है कि आप: कि आप कंपोज़ेबल सिर्फ़ उनकी ज़रूरत के हिसाब से पास करें. अलग करने को बढ़ावा देने के लिए और कंपोज़ेबल का दोबारा इस्तेमाल करने के लिए, हर कंपोज़ेबल में कम से कम जानकारी दी जा सकती है.
@Composable fun MyComposable(myViewModel: MyViewModel = viewModel()) { // ... MyDescendant(myViewModel.data) } // Don't pass the whole object! Just what the descendant needs. // Also, don't pass the ViewModel as an implicit dependency using // a CompositionLocal. @Composable fun MyDescendant(myViewModel: MyViewModel) { /* ... */ } // Pass only what the descendant needs @Composable fun MyDescendant(data: DataToDisplay) { // Display data }
कंट्रोल में बदलाव
किसी कंपोज़ेबल में गै़र-ज़रूरी डिपेंडेंसी पास होने से रोकने का एक और तरीका है कंट्रोल में बदलाव करके. डिसेंडेंट को हासिल करने के बजाय, कुछ लॉजिक लागू करता है, तो पैरंट ऐसा करता है.
नीचे दिया गया उदाहरण देखें, जहां डिसेंडेंट को कुछ डेटा लोड करें:
@Composable fun MyComposable(myViewModel: MyViewModel = viewModel()) { // ... MyDescendant(myViewModel) } @Composable fun MyDescendant(myViewModel: MyViewModel) { Button(onClick = { myViewModel.loadData() }) { Text("Load data") } }
मामले के आधार पर, MyDescendant
की कई ज़िम्मेदारी हो सकती हैं. साथ ही,
MyViewModel
को डिपेंडेंसी के तौर पर पास करने से, MyDescendant
का फिर से इस्तेमाल कम हो जाता है
वे अब एक साथ जुड़ गए हैं. उस विकल्प पर विचार करें जो
डिसेंडेंट पर निर्भर होता है और कंट्रोल के सिद्धांतों के उलटा इस्तेमाल करता है जो
इस नियम के लागू होने के लिए, एंसेस्टर की ज़िम्मेदारी तय होती है:
@Composable fun MyComposable(myViewModel: MyViewModel = viewModel()) { // ... ReusableLoadDataButton( onLoadClick = { myViewModel.loadData() } ) } @Composable fun ReusableLoadDataButton(onLoadClick: () -> Unit) { Button(onClick = onLoadClick) { Text("Load data") } }
यह तरीका, कुछ इस्तेमाल के मामलों में बेहतर हो सकता है, क्योंकि इससे अपने करीबी पूर्वजों से मिलता है. ऐंसेस्टर कंपोज़ेबल में दिखने वाले नए फ़ॉर्मैट की तुलना में, यह कॉम्प्लेक्स, लोअर-लेवल के ज़्यादा लचीले कंपोज़ेबल होने के लिए डिज़ाइन किया गया है.
इसी तरह, @Composable
सामग्री lambdas का इस्तेमाल
एक जैसे फ़ायदे:
@Composable fun MyComposable(myViewModel: MyViewModel = viewModel()) { // ... ReusablePartOfTheScreen( content = { Button( onClick = { myViewModel.loadData() } ) { Text("Confirm") } } ) } @Composable fun ReusablePartOfTheScreen(content: @Composable () -> Unit) { Column { // ... content() } }
आपके लिए सुझाव
- ध्यान दें: JavaScript बंद होने पर लिंक टेक्स्ट दिखता है
- Compose में किसी थीम की एनाटॉमी
- Compose में व्यू का इस्तेमाल करना
- Jetpack Compose के लिए Kotlin