Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रणाली >> Android

Jetpack Compose बेसिक्स मास्टर करें: कंपोजेबल और रीकंपोजिशन के लिए शुरुआती गाइड

यह ट्यूटोरियल आपको Android पर Jetpack Compose UI लाइब्रेरी से संबंधित कुछ मौलिक अवधारणाओं और शर्तों को सिखाएगा।

हालांकि यह Compose के लिए एक शुरुआती गाइड है, यह Android के लिए शुरुआती गाइड नहीं होगा – इसलिए आपको कम से कम एक या दो एप्लिकेशन बनाए होने चाहिए (हालांकि Compose में नहीं, जरूरी नहीं)।

शुरू करने से पहले, मैं शुरुआत में Leland Richardson के दो भागों वाले लेख श्रृंखला को पार करने तक सीनियर डेवलपर्स की ओर निर्देशित एक फॉलो-अप लेख लिखने की योजना बना रहा था। Leland न केवल Jetpack Compose टीम पर काम करने वाले एक सॉफ़्टवेयर इंजीनियर हैं, बल्कि मैं देखता हूं कि वे एक महान लेखक भी हैं।

जबकि मुझे लगता है कि मेरा लेख Jetpack Compose की मूल बातें के परिचय के रूप में अपने आप में खड़ा होगा, मैं दृढ़ता से सुझाव देता हूं कि आप उनके लेख पढ़ें एक बार जब आप Compose के साथ कुछ व्यावहारिक अनुभव प्राप्त कर लें (या तुरंत यदि आप उस तरह से सीखना पसंद करते हैं)।

इस लेख में समझाई गई मुख्य शर्तें/अवधारणाएं:

  • पुराने View सिस्टम और पदानुक्रम का संक्षिप्त पुनर्कथन
  • कंपोजेबल और वे Views के संबंध में कैसे खड़े हैं
  • रीकंपोजिशन और इसे बहुत खराब तरीके से करने से कैसे बचें!

कंपोजेबल क्या है?

इस खंड में, हम Jetpack Compose लाइब्रेरी के सबसे मूलभूत हिस्से पर चर्चा करेंगे। यदि आप एक अनुभवी Android डेवलपर हैं, तो आप "Are Composables Views?" शीर्षक वाले उप-अनुभाग पर छोड़ना चाह सकते हैं।

यदि आप पहले से View सिस्टम से परिचित नहीं हैं, तो आपको अगला खंड पढ़ना चाहिए क्योंकि यह समझने के लिए आवश्यक है कि कंपोजेबल क्या है।

View पदानुक्रम

Android SDK के संदर्भ में (वे लाइब्रेरी जिनका उपयोग हम इस प्लेटफॉर्म पर यूजर इंटरफेस बनाने के लिए करते हैं), एक View वह है जिसका उपयोग हम अपने एप्लिकेशन को संरचना और स्टाइल देने के लिए करते हैं।

यह किसी दिए गए यूजर इंटरफेस (UI) का सबसे मौलिक प्रकार का बिल्डिंग ब्लॉक या तत्व है, और इन बिल्डिंग ब्लॉक्स में से प्रत्येक में निम्न प्रकार की जानकारी होगी (अन्य चीजों के अलावा):

  • X और Y प्रारंभ और अंत स्थितियां जो कंप्यूटर को बताती हैं कि डिवाइस स्क्रीन पर व्यू कहां खींचना है
  • रंग और अल्फा (पारदर्शिता) मान
  • फॉन्ट जानकारी, टेक्स्ट, प्रतीक, और छवियां
  • इवेंट के आधार पर व्यवहार जैसे उपयोगकर्ता इंटरैक्शन (क्लिक) या एप्लिकेशन के डेटा में परिवर्तन (इस पर बाद में)

यह समझना महत्वपूर्ण है कि एक View एक बटन जैसी चीज हो सकती है (आमतौर पर "विजेट" कहा जाता है), लेकिन यह पूरी स्क्रीन, स्क्रीन के हिस्से, या अन्य चाइल्ड Views के लिए एक कंटेनर भी हो सकता है।

ऐसे कंटेनर आमतौर पर संदर्भ के आधार पर Layouts या Viewgroups कहलाते हैं। और, विजेट के समान अधिकांश प्रकार की जानकारी साझा करते हुए, उनमें इस बारे में जानकारी भी होती है कि उनके भीतर नेस्टेड अन्य Views को कैसे व्यवस्थित और प्रदर्शित किया जाए।

इसे ध्यान में रखते हुए, हम इस View सिस्टम की समीक्षा के महत्वपूर्ण भाग पर पहुंचते हैं: View पदानुक्रम। वेब डेवलपर्स के लिए, View पदानुक्रम अनिवार्य रूप से Android का डॉक्यूमेंट ऑब्जेक्ट मॉडल (DOM) संस्करण है।

Android डेवलपर्स के लिए, आप View पदानुक्रम को उन सभी Views के वर्चुअल प्रतिनिधित्व के रूप में सोच सकते हैं जिन्हें आपने या तो XML फाइलों में या Java या Kotlin में प्रोग्रामेटिक रूप से परिभाषित किया था।

इसे स्पष्ट करने के लिए, आइए ऐसी XML फाइल को देखें (इसे बारीकी से अध्ययन करने की कोई आवश्यकता नहीं है, बस नामों पर ध्यान दें)। फिर, एक डीबगर/स्टेपर टूल का उपयोग करके, हम देखेंगे कि यह Fragment के मेमोरी स्पेस में कैसा दिखता है जो इस फाइल को इन्फ्लेट करता है:

fragment_hour_view.xml:

<?xml version=”1.0" encoding=”utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android=”https://schemas.android.com/apk/res/android" android:layout_width=”match_parent” android:layout_height=”match_parent” android:id=”@+id/root_hour_view_fragment” xmlns:app=”https://schemas.android.com/apk/res-auto" > <androidx.compose.ui.platform.ComposeView android:id=”@+id/tlb_hour_view” //... /> <com.wiseassblog.samsaradayplanner.ui.managehourview.HourToggleView android:id=”@+id/vqht_one” //... /> <com.wiseassblog.samsaradayplanner.ui.managehourview.HourToggleView android:id=”@+id/vqht_two” //... /> <com.wiseassblog.samsaradayplanner.ui.managehourview.HourToggleView android:id=”@+id/vqht_three” //... /> <com.wiseassblog.samsaradayplanner.ui.managehourview.HourToggleView android:id=”@+id/vqht_four” //... /> </androidx.constraintlayout.widget.ConstraintLayout>

Fragment के मेमोरी स्पेस (HourView.kt):

Jetpack Compose बेसिक्स मास्टर करें: कंपोजेबल और रीकंपोजिशन के लिए शुरुआती गाइड
View पदानुक्रम की छवि

डीबगर और स्टेपर टूल विभिन्न लाइब्रेरी से मेरे द्वारा उपयोग किए जाने वाले कोड के हुड के नीचे क्या चल रहा है, इसके बारे में जानने के मेरे पसंदीदा तरीकों में से कुछ हैं। इसे कभी आजमाएं!

आपको यह XML फाइल और यह दिखाने का उद्देश्य कि यह एक प्रक्रिया में क्या बन जाता है (एक प्रक्रिया बस एक चल रहा प्रोग्राम है डिवाइस पर), यह प्रदर्शित करना है कि XML फाइल में नेस्टेड Views रनटाइम पर नेस्टेड View पदानुक्रम में कैसे अनुवाद करते हैं।

उम्मीद है, पुराने सिस्टम के काम करने के एक सरल लेकिन ठोस मॉडल के साथ, हम इसकी तुलना नए के साथ कर सकते हैं।

क्या कंपोजेबल Views हैं?

यह उन पहले प्रश्नों में से एक था जो मैंने Compose के साथ काम करना शुरू करते समय पूछा था, और जिस उत्तर पर मैं पहुंचा हूं वह हां और नहीं दोनों है।

हां, इस अर्थ में कि एक कंपोजेबल पुराने सिस्टम में View के समान संकल्पनात्मक भूमिका को पूरा करता है। एक कंपोजेबल एक विजेट हो सकता है जैसे बटन, या ConstraintLayout जैसा कंटेनर (यह ध्यान देने योग्य है कि ConstraintLayout का एक कंपोजेबल कार्यान्वयन उपलब्ध है)।

नहीं, इस अर्थ में कि UI को अब View पदानुक्रम में वर्चुअली प्रतिनिधित्व नहीं किया जाता है (इंटरऑपरेबिलिटी से जुड़ी स्थितियों को छोड़कर)। इसके साथ कहा गया है, Compose UI को वर्चुअली प्रतिनिधित्व करने और ट्रैक रखने के लिए जादू का उपयोग नहीं करता है। इसका मतलब है कि इसके पास अपनी खुद की चीज होनी चाहिए जो संकल्पनात्मक रूप से View पदानुक्रम के समान हो।

आइए इस चीज पर बहुत संक्षिप्त नज़र डालें। यहां, हमारे पास एक Activity है जो खुद से एक कंपोजेबल को बांधने के लिए setContent {…} फ़ंक्शन का उपयोग करती है:

ActiveGameActivity.kt:

class ActiveGameActivity : AppCompatActivity(), ActiveGameContainer { private lateinit var logic: ActiveGameLogic override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val viewModel = ActiveGameViewModel() setContent { ActiveGameScreen( onEventHandler = { logic.onEvent(it) }, viewModel ) } logic = buildActiveGameLogic(this, viewModel, applicationContext) } //… }

ActiveGameScreen.kt:

@Composable fun ActiveGameScreen( onEventHandler: ((ActiveGameEvent) -> Unit), viewModel: ActiveGameViewModel ) { //... GraphSudokuTheme { Column( Modifier .background(MaterialTheme.colors.primary) .fillMaxHeight() ) { ActiveGameToolbar( clickHandler = { onEventHandler.invoke( ActiveGameEvent.OnNewGameClicked ) } ) Box { //content } } } }

Compose में, View पदानुक्रम को किसी ऐसी चीज से बदल दिया जाता है जिसे हम इस Activity के mWindow फील्ड में गहराई से खोदकर ढूंढ सकते हैं। उस फील्ड के भीतर View पदानुक्रम की संकल्पनात्मक प्रतिस्थापन है: द Composer और उसका slotTable।

Jetpack Compose बेसिक्स मास्टर करें: कंपोजेबल और रीकंपोजिशन के लिए शुरुआती गाइड

इस बिंदु पर, यदि आप Composer और इसके slotTable का विस्तृत अवलोकन चाहते हैं, तो मुझे फिर से Leland के लेख का सुझाव देना होगा (वह भाग 2 में विस्तार से जाता है)। Compose पदानुक्रम में Composer और इसके slotTable से अधिक है, लेकिन यह हमें शुरू करने के लिए पर्याप्त होना चाहिए।

सामान्य शब्दों में, Jetpack Compose जिसे हम Compose पदानुक्रम कह सकते हैं उसका उपयोग करता है (जो Composer और इसके slotTable जैसी चीजों से बना और प्रबंधित होता है)।

फिर से, यह View पदानुक्रम के समान संकल्पनात्मक विचार है, मेमोरी स्पेस में ऑब्जेक्ट्स का एक समूह जो सामूहिक रूप से UI का प्रतिनिधित्व करता है, लेकिन इसे बहुत अलग तरीके से लागू किया गया है।

एक महत्वपूर्ण अंतर है, हालांकि, जिसे तकनीकी रूप से समझना मुश्किल है, लेकिन सिद्धांत में समझना आसान है। यह वह तरीका है जिससे Compose Compose पदानुक्रम के अपडेट को संभालता है: रीकंपोजिशन।

रीकंपोजिशन: Compose UI को कैसे अपडेट करें

मेरे ESL दोस्तों के लिए, शब्द Compose लैटिन componere से आया है, जिसका मोटे तौर पर अर्थ है "एक साथ रखना।" जो कोई संगीत लिखता है उसे अक्सर "कंपोजर" कहा जाता है, जिसे एक या अधिक वाद्ययंत्रों से आने वाले नोट्स को एक रचना (गीत) में एक साथ रखने वाले के रूप में सोचा जा सकता है।

एक साथ रखना तात्पर्य है कि व्यक्तिगत टुकड़े हैं। यह समझना महत्वपूर्ण है कि लगभग कोई भी अच्छा सॉफ़्टवेयर डेवलपर अपने कोड को सबसे छोटे उचित भागों में तोड़ने का कम से कम कुछ प्रयास करता है।

मैं उचित का उल्लेख करता हूं, क्योंकि मुझे लगता है कि DRY (Don't Repeat Yourself) जैसे सिद्धांतों का पालत केवल उस हद तक किया जाना चाहिए जहां वे उनके द्वारा बनाई गई समस्याओं से अधिक हल करते हैं।

इस अवधारणा को लागू करने के कई लाभ हैं, जिसे अक्सर मॉड्यूलैरिटी कहा जाता है (या जैसा कि मैं पसंद करता हूं, चिंताओं का पृथक्करण, या SOC)। मुझे पता है कि आप में से कुछ इसे पढ़कर सोच सकते हैं कि मैं सिर्फ Leland ने अपने लेख में जो कहा उसे कॉपी कर रहा हूं, लेकिन मैं कई वर्षों से SOC को किसी भी अच्छे आर्किटेक्चर के स्वर्ण सिद्धांत के रूप में बता रहा हूं।

जहां यह Compose में खेलता है, वह वही सिद्धांत है जो हम लोकप्रिय Javascript लाइब्रेरी React में देखते हैं। जब सही ढंग से किया जाता है, तो Compose केवल उन कंपोजेबल्स (UI के भागों/तत्वों) को "रीकंपोज" करेगा (रीड्रॉ, री-रेंडर, अपडेट, जो भी हो) जिन्हें रीकंपोज करने की आवश्यकता होती है।

यह एप्लिकेशन के प्रदर्शन के मामले में बेहद महत्वपूर्ण है। ऐसा इसलिए है क्योंकि UI को रीड्रॉ करना, चाहे पुराने View सिस्टम में हो या Compose में, सिस्टम संसाधनों के लिए महंगा है।

यदि आप जानते नहीं थे, तो पुराने RecyclerView (जो 2016 में मैंने पहली बार ट्यूटोरियल बनाया था!) का पूरा उद्देश्य डेटा की सूची में ViewHolder पैटर्न को नियोजित करना था। इसने प्रत्येक सूची आइटम के लिए लगातार नए Views को इन्फ्लेट (बनाने) की आवश्यकता से बचा लिया।

इस लेख में मेरा लक्ष्य ज्यादातर सिद्धांत पर ध्यान केंद्रित करना था, क्योंकि मैं अगले कुछ महीनों में बहुत सारी व्यावहारिक सामग्री लिखूंगा। हालांकि, मैं अपने सीधे अनुभव से एक कहानी के साथ लेख को समाप्त करूंगा, जो आपको यह समझने में मदद करेगी कि रीकंपोजिशन कैसे काम करता है, और इसे बहुत खराब तरीके से करने से कैसे बचें!

स्टॉपवॉच उदाहरण

मेरे पहले पूर्ण Compose एप्लिकेशन के लिए, मैंने Sudoku बनाने का फैसला किया। कई कारण हैं, जिनमें यह तथ्य भी शामिल है कि मैं एक ऐसा प्रोजेक्ट चाहता था जिसमें बेहद जटिल UI न हो। मैं ग्राफ DS और एल्गोस में गहरा गोता लगाने का मौका भी चाहता था, जो Sudoku पहेलियों के लिए काफी उपयुक्त हैं।

एक चीज जो मैं चाहता था वह थी एक स्टॉपवॉच जो ट्रैक करे कि उपयोगकर्ता को पहेली पूरी करने में कितना समय लगा:

Jetpack Compose बेसिक्स मास्टर करें: कंपोजेबल और रीकंपोजिशन के लिए शुरुआती गाइड
Graph Sudoku पहेली

जैसा कि अक्सर मेरे पेशे में होता है, मुझे उम्मीद थी कि इस टाइमर को जोड़ना वास्तव में जितना आसान था, उससे कहीं अधिक आसान होगा। मैंने Android के Chronometer क्लास के साथ-साथ Java Timer क्लास के साथ खिलवाड़ किया, और उन दोनों ने अलग-अलग लेकिन फिर भी एप्लिकेशन-ब्रेकिंग समस्याएं पेश कीं।

आखिरकार मैंने एक कदम पीछे लिया और महसूस किया कि मैं Kotlin में लिख रहा था। इसलिए मैंने अपनी प्रेजेंटेशन लॉजिक क्लास में एक कोरूटीन-आधारित टाइमर सेट किया (वहां रखना सबसे ज्यादा समझ में आया), जो हर सेकंड मेरे व्यूमॉडल को अपडेट करेगा:

Class ActiveGameLogic(…):…{ //… inline fun startCoroutineTimer( delayMillis: Long = 0, repeatMillis: Long = 1000, crossinline action: () -> Unit ) = launch { delay(delayMillis) if (repeatMillis > 0) { while (true) { action() delay(repeatMillis) } } else { action() } } private fun onStart() = launch { gameRepo.getCurrentGame( { puzzle, isComplete -> viewModel.initializeBoardState( puzzle, isComplete ) if (!isComplete) timerTracker = startCoroutineTimer { viewModel.updateTimerState() } },{ container?.onNewGameClick() }) } //… }

ViewModel (AAC से नहीं – मैं अपने खुद के VM लिखता हूं। लेकिन Compose में AAC VMs के साथ अच्छा इंटरऑपरेबिलिटी है जो मैं देख सकता हूं।) कॉलबैक फ़ंक्शन के संदर्भों को उजागर करता है, जिनका उपयोग मैं अपने कंपोजेबल को अपडेट करने के लिए करूंगा:

class ActiveGameViewModel { //… internal var subTimerState: ((Long) -> Unit)? = null internal var timerState: Long = 0L //… internal fun updateTimerState(){ timerState++ subTimerState?.invoke(timerState) } //… }

अब महत्वपूर्ण भाग आता है! हम remember फ़ंक्शन जैसी Compose की कुछ विशेषताओं का उपयोग करके Compose पदानुक्रम के रीकंपोजिशन को ट्रिगर कर सकते हैं:

var timerState by remember { mutableStateOf(“”) }

यदि आपको पता होना चाहिए, तो ये सुविधाएं आप जो याद कर रहे हैं उसकी स्थिति को slotTable में स्टोर करती हैं। संक्षेप में, यहां शब्द state का अर्थ डेटा की वर्तमान "स्थिति" है, जो सिर्फ एक खाली String के रूप में शुरू होती है।

यहां वह जगह है जहां मैंने चीजों को खराब कर दिया। मैंने अपने सरल टाइमर कंपोजेबल को अपने फ़ंक्शन में खींच लिया था (SOC लागू किया), और मैं उस कंपोजेबल को पैरामीटर के रूप में timerState पास कर रहा था।

हालांकि, उपरोक्त स्निपेट टाइमर के पैरेंट कंपोजेबल में बैठे थे, जो UI के सबसे जटिल हिस्से के लिए एक कंटेनर था (9x9 Sudoku के लिए बड़ी संख्या में विजेट की आवश्यकता होती है):

@Composable fun GameContent( onEventHandler: (ActiveGameEvent) -> Unit, viewModel: ActiveGameViewModel ) { Surface( Modifier .wrapContentHeight() .fillMaxWidth() ) { BoxWithConstraints(Modifier.background(MaterialTheme.colors.primary)) { //… ConstraintLayout { val (board, timer, diff, inputs) = createRefs() var isComplete by remember { mutableStateOf(false) } var timerState by remember { mutableStateOf("") } viewModel.subTimerState = { timerState = it.toTime() } viewModel.subIsCompleteState = { isComplete = it } //…Sudoku बोर्ड //Timer Box(Modifier .wrapContentSize() .constrainAs(timer) { top.linkTo(board.bottom) start.linkTo(parent.start) } .padding(start = 16.dp)) { TimerText(timerState) } //…कठिनाई प्रदर्शन //…इनपुट बटन } } } } @Composable fun TimerText(timerState: String) { Text( text = timerState, style = activeGameSubtitle.copy(color = MaterialTheme.colors.secondary) ) }

यह काफी अंतराल और अनुत्तरदेयता पैदा कर रहा था। डीबगर का भारी उपयोग करके, मुझे पता चला कि क्यों। क्योंकि मेरा timerState वेरिएबल पैरेंट Composable के अंदर बनाया और अपडेट किया गया था, यह UI के उस पूरे हिस्से के रीकंपोजिशन को ट्रिगर कर रहा था। हर. एकल. टिक।

उपयुक्त कोड को TimerText कंपोजेबल में ले जाने के बाद, चीजें बहुत आसानी से काम करती थीं:

@Composable fun TimerText(viewModel: ActiveGameViewModel) { var timerState by remember { mutableStateOf("") } viewModel.subTimerState = { timerState = it.toTime() } Text( text = timerState, style = activeGameSubtitle.copy(color = MaterialTheme.colors.secondary) ) }

उम्मीद है कि मैंने आपको रीकंपोजिशन की एक कार्यशील समझ दी है और इसे गलत तरीके से करने के सबसे बड़े तरीकों में से एक।

अनावश्यक रीकंपोजिशन से बचना प्रदर्शन के लिए अविश्वसनीय रूप से महत्वपूर्ण है। और अब तक ऐसा लगता है कि SOC को सख्ती से लागू करना, यहां तक कि अलग-अलग कंपोजेबल में याद रखने की स्थिति को रखने की हद तक, मानक अभ्यास बन जाना चाहिए।

संसाधन और समर्थन

यदि आपको यह लेख पसंद आया, तो कृपया इसे सोशल मीडिया पर साझा करें और यहां freeCodeCamp पर मेरे अन्य लेख देखें। मेरा एक YouTube चैनल भी है जिसमें सैकड़ों ट्यूटोरियल हैं, और मैं विभिन्न प्लेटफार्मों पर एक सक्रिय लेखक हूं।

सोशल मीडिया पर मुझसे जुड़ें

आप मुझे यहां Instagram पर और यहां Twitter पर पा सकते हैं।

साथ ही, मैं उस एकल संसाधन को इंगित करना चाहता हूं जिसका उपयोग मैंने Jetpack Compose के साथ शुरू करने के लिए किया था: अच्छे डेवलपर्स से काम करने वाले कोड नमूने।

  1. एंड्रॉइड पर iPhone इमोजी कैसे देखें एंड्रॉइड पर iPhone इमोजी कैसे देखें

    इस बात से इनकार नहीं किया जा सकता कि iPhone इमोजी कमाल के हैं, लेकिन क्या होगा अगर आप एंड्रॉइड डिवाइस के साथ आने वाली विविधता पसंद करते हैं? आप अभी भी एंड्रॉइड पर iPhone इमोजी देख सकते हैं। यह बहुत अच्छी खबर है अगर आप iPhone से एंड्रॉइड पर स्विच कर रहे हैं और अपने पसंदीदा इमोजी तक पहुंच चाहते हैं। ज

  1. Android विजिबिलिटी लिसनर्स में मास्टरी: व्यू विजिबिलिटी ट्रैक करने का तरीका और कारण Android विजिबिलिटी लिसनर्स में मास्टरी: व्यू विजिबिलिटी ट्रैक करने का तरीका और कारण

    Android UI व्यूज़ से बना होता है, और एक सामान्य ऐप्लिकेशन में आमतौर पर कई व्यूज़ होते हैं। यह जानने के लिए कि यूज़र वर्तमान में किस व्यू को देख रहा है, आपको विजिबिलिटी लिसनर्स इंस्टॉल करने होंगे।व्यू के विजिबिलिटी स्टेटस की पहचान करने के लिए आपके पास मौजूद विभिन्न विकल्पों के बारे में जानने के लिए आ

  1. Kotlin Android एनिमेशन को एक्सेसिबल बनाना: एक व्यावहारिक गाइड Kotlin Android एनिमेशन को एक्सेसिबल बनाना: एक व्यावहारिक गाइड

    जब मैंने अपनी पहली Android योगदान के लिए उदाहरणों पर शोध किया, तो Kotlin में लिखी गई एनिमेशन के कुछ ही उदाहरण मौजूद थे। नेटिव एनिमेशन के भीतर एक्सेसिबिलिटी विचारों के कोड उदाहरण भी बहुत कम थे। तो चलिए शुरू करते हैं! आइए Kotlin में एक नेटिव एक्सपैंड एनिमेशन लिखने को देखते हैं, और बात करते हैं कि Tal