अपना Compose यूज़र इंटरफ़ेस (यूआई) डिज़ाइन करना

'लिखें' फ़ील्ड में, यूज़र इंटरफ़ेस (यूआई) में बदलाव नहीं किया जा सकता. ऐसा करने के बाद इसे अपडेट नहीं किया जा सकता बनाए गए आपके पास यूज़र इंटरफ़ेस (यूआई) की स्थिति को कंट्रोल करने का विकल्प है. हर बार यूज़र इंटरफ़ेस (यूआई) में बदलाव, कंपोज़ यूज़र इंटरफ़ेस ट्री के उन हिस्सों को फिर से बनाता है जिनमें बदला गया. कंपोज़ेबल स्वीकार किए जा सकते हैं इवेंट की स्थिति तय करता है और उन्हें दिखाता है—उदाहरण के लिए, TextField कोई वैल्यू स्वीकार करता है और उसे सार्वजनिक करता है एक कॉलबैक onValueChange जो कॉलबैक हैंडलर से अनुरोध करता है कि वह वैल्यू.

var name by remember { mutableStateOf("") }
OutlinedTextField(
    value = name,
    onValueChange = { name = it },
    label = { Text("Name") }
)

कंपोज़ेबल, स्थिति को स्वीकार करते हैं और इवेंट दिखाते हैं, इसलिए एकतरफ़ा डेटा फ़्लो पैटर्न, Jetpack Compose के साथ अच्छी तरह से फ़िट होता है. इस गाइड में, कन्वर्ज़न ट्रैकिंग की सुविधा को Compose में एकतरफ़ा डेटा फ़्लो पैटर्न, इवेंट लागू करने का तरीका और स्टेट होल्डर और कंपोज़ में ViewModels के साथ काम करने का तरीका जानना है.

एकतरफ़ा डेटा फ़्लो

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

एकतरफ़ा डेटा फ़्लो का इस्तेमाल करने वाले ऐप्लिकेशन के लिए, यूज़र इंटरफ़ेस (यूआई) अपडेट लूप इस तरह दिखता है:

  • इवेंट: यूज़र इंटरफ़ेस (यूआई) का कुछ हिस्सा इवेंट जनरेट करता है और उसे ऊपर की ओर भेजता है, जैसे कि मैनेज करने के लिए ViewModel को पास किया गया बटन क्लिक; या किसी इवेंट को इस तरह से माइग्रेट किया जाता है: आपके ऐप्लिकेशन की अन्य लेयर, जैसे कि उपयोगकर्ता सेशन में समयसीमा खत्म हो गई है.
  • स्थिति अपडेट करें: कोई इवेंट हैंडलर स्थिति बदल सकता है.
  • डिसप्ले स्टेट: स्टेट होल्डर स्टेट से आगे बढ़ जाता है और यूज़र इंटरफ़ेस (यूआई) दिखता है इसे.

पहली इमेज. एकतरफ़ा डेटा फ़्लो.

Jetpack Compose का इस्तेमाल करते समय इस पैटर्न को फ़ॉलो करने के कई फ़ायदे हैं:

  • टेस्टेबिलिटी: यूज़र इंटरफ़ेस (यूआई) से डिकपलिंग स्टेट, जो इसे दिखाता है, इससे काम आसान हो जाता है दोनों को अलग-अलग टेस्ट कर सकें.
  • स्टेट इनकैप्सुलेशन: क्योंकि स्टेट को सिर्फ़ एक जगह पर अपडेट किया जा सकता है और कंपोज़ेबल की स्थिति के बारे में सिर्फ़ एक सोर्स होता है, लेकिन अलग-अलग स्थितियों की वजह से गड़बड़ियां हो सकती हैं.
  • यूज़र इंटरफ़ेस (यूआई) एक जैसा होना: सभी स्टेटस अपडेट, यूज़र इंटरफ़ेस (यूआई) में इसके हिसाब से तुरंत दिखने लगते हैं ऑब्ज़र्वेबल स्टेट होल्डर का इस्तेमाल, जैसे कि StateFlow या LiveData.

Jetpack Compose में एक-तरफ़ा डेटा फ़्लो

कंपोज़ेबल, राज्य और इवेंट के आधार पर काम करते हैं. उदाहरण के लिए, TextField सिर्फ़ यह तब अपडेट होता है, जब इसका value पैरामीटर अपडेट होता है और यह onValueChange दिखाता है कॉलबैक—यह एक ऐसा इवेंट है जिसमें वैल्यू को नई वैल्यू में बदलने का अनुरोध किया जाता है. लिखें State ऑब्जेक्ट को वैल्यू होल्डर के तौर पर तय करता है और स्टेट वैल्यू में बदलाव करता है रीकंपोज़िशन को ट्रिगर कर सकती है. राज्य को remember { mutableStateOf(value) } या आपको कितनी देर तक इस्तेमाल करना है, इसके आधार पर rememberSaveable { mutableStateOf(value) याद रखें.

TextField कंपोज़ेबल की वैल्यू String है, इसलिए यह कहीं से भी—हार्डकोड किए गए मान से, ViewModel से या पैरंट कंपोज़ेबल. आपको इसे State ऑब्जेक्ट में रखने की ज़रूरत नहीं है, लेकिन आपको चाहिए ताकि onValueChange को कॉल करने पर वैल्यू को अपडेट किया जा सके.

कंपोज़ेबल पैरामीटर तय करें

किसी कंपोज़ेबल के स्टेट पैरामीटर तय करते समय, आपको इन बातों का ध्यान रखना चाहिए इन सवालों के जवाब दें:

  • कंपोज़ेबल को फिर से इस्तेमाल या ज़रूरत के हिसाब से कैसे बनाया जा सकता है?
  • स्टेट पैरामीटर, इस कंपोज़ेबल की परफ़ॉर्मेंस पर कैसे असर डालते हैं?

अलग-अलग कंपोज़ेबल को डीकपलिंग और दोबारा इस्तेमाल करने के लिए, हर कंपोज़ेबल में कम से कम वैल्यू होनी चाहिए जानकारी होती है. उदाहरण के लिए, एक कंपोज़ेबल बनाते समय हेडर में बदलाव कर सकते हैं. साथ ही, सिर्फ़ वह जानकारी दें जिसे नहीं, बल्कि पूरा समाचार लेख दिखाएं:

@Composable
fun Header(title: String, subtitle: String) {
    // Recomposes when title or subtitle have changed.
}

@Composable
fun Header(news: News) {
    // Recomposes when a new instance of News is passed in.
}

कभी-कभी, अलग-अलग पैरामीटर का इस्तेमाल करने से भी परफ़ॉर्मेंस बेहतर होती है. उदाहरण के लिए, अगर News में title और subtitle के अलावा भी ज़्यादा जानकारी मौजूद होती है, जब भी वह News का नया इंस्टेंस Header(news) में पास किया जाता है, तो कंपोज़ेबल फिर से बनाएं, भले ही title और subtitle में कोई बदलाव न हुआ हो.

पास किए जाने वाले पैरामीटर की संख्या पर ध्यान दें. फ़ंक्शन के साथ बहुत ज़्यादा पैरामीटर, फ़ंक्शन के एर्गोनॉमिक्स को कम कर देते हैं, इसलिए इस मामले में उन्हें क्लास में ग्रुप में रखने का सुझाव दिया जाता है.

Compose में इवेंट

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

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

स्थिति और इवेंट हैंडलर lambdas के लिए, ऐसी वैल्यू पास करने को प्राथमिकता दें जिनमें बदलाव न किए जा सकते हों. यह इस तरीके को अपनाने के ये फ़ायदे हैं:

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

उदाहरण के लिए, String और Lambda फ़ंक्शन को पैरामीटर के तौर पर स्वीकार करने वाला कंपोज़ेबल इन्हें कई कॉन्टेक्स्ट से कॉल किया जा सकता है. साथ ही, इन्हें फिर से इस्तेमाल किया जा सकता है. मान लीजिए कि मुख्य ऐप्लिकेशन बार पर टेक्स्ट दिखता है और उसमें 'वापस जाएं' बटन होता है. आप ज़्यादा सामान्य MyAppTopAppBar कंपोज़ेबल, जिसमें टेक्स्ट के साथ-साथ पीछे का हिस्सा दिखता है बटन हैंडल को पैरामीटर के तौर पर चुनें:

@Composable
fun MyAppTopAppBar(topAppBarText: String, onBackPressed: () -> Unit) {
    TopAppBar(
        title = {
            Text(
                text = topAppBarText,
                textAlign = TextAlign.Center,
                modifier = Modifier
                    .fillMaxSize()
                    .wrapContentSize(Alignment.Center)
            )
        },
        navigationIcon = {
            IconButton(onClick = onBackPressed) {
                Icon(
                    Icons.Filled.ArrowBack,
                    contentDescription = localizedString
                )
            }
        },
        // ...
    )
}

ViewModels, स्थितियां, और इवेंट: एक उदाहरण

ViewModel और mutableStateOf का इस्तेमाल करके, एकतरफ़ा डेटा भी पेश किया जा सकता है फ़्लो को सही जगह पर रखें, अगर इनमें से कोई एक बात सही है:

  • आपके यूज़र इंटरफ़ेस (यूआई) की स्थिति, StateFlow या LiveData जैसे मॉनिटर किए जा सकने वाले स्टेट होल्डर से सार्वजनिक की जाती है.
  • ViewModel, आपके ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) या अन्य लेयर से आने वाले इवेंट को मैनेज करता है और इवेंट के आधार पर स्टेट होल्डर को अपडेट करता है.

उदाहरण के लिए, साइन-इन स्क्रीन चालू करते समय, साइन इन करें बटन पर टैप करें ऐप्लिकेशन में, प्रोग्रेस स्पिनर और नेटवर्क कॉल दिखने चाहिए. अगर लॉगिन हो गया है, फिर आपका ऐप्लिकेशन किसी दूसरी स्क्रीन पर चला जाता है; अगर ऐप्लिकेशन में स्नैकबार दिखने की गड़बड़ी का पता चलता है. यहां बताया गया है कि स्क्रीन के स्टेटस को कैसे मॉडल किया जाएगा और इवेंट:

स्क्रीन पर चार स्थितियां दिखती हैं:

  • साइन आउट होने पर: जब उपयोगकर्ता ने अभी तक साइन इन न किया हो.
  • प्रोसेस जारी है: जब आपका ऐप्लिकेशन फ़िलहाल इस तरीके से उपयोगकर्ता को साइन इन करने की कोशिश कर रहा हो नेटवर्क कॉल किया जा रहा है.
  • गड़बड़ी: साइन इन करते समय कोई गड़बड़ी होने की जानकारी.
  • साइन इन किया हुआ है: जब उपयोगकर्ता ने साइन इन किया हुआ हो.

इन राज्यों को सील की गई क्लास के तौर पर मॉडल किया जा सकता है. ViewModel राज्य को इस तरह दिखाता है State, शुरुआती स्थिति सेट करता है और ज़रूरत के हिसाब से स्थिति अपडेट करता है. कॉन्टेंट बनाने ViewModel, साइन-इन इवेंट को मैनेज करने के लिए, onSignIn() तरीका भी इस्तेमाल करता है.

class MyViewModel : ViewModel() {
    private val _uiState = mutableStateOf<UiState>(UiState.SignedOut)
    val uiState: State<UiState>
        get() = _uiState

    // ...
}

mutableStateOf API के अलावा, Compose उपलब्ध कराता है इनके लिए एक्सटेंशन LiveData, Flow, और लिसनर के तौर पर रजिस्टर करने और वैल्यू को राज्य के तौर पर दिखाने के लिए, Observable का इस्तेमाल करें.

class MyViewModel : ViewModel() {
    private val _uiState = MutableLiveData<UiState>(UiState.SignedOut)
    val uiState: LiveData<UiState>
        get() = _uiState

    // ...
}

@Composable
fun MyComposable(viewModel: MyViewModel) {
    val uiState = viewModel.uiState.observeAsState()
    // ...
}

ज़्यादा जानें

Jetpack Compose में आर्किटेक्चर के बारे में ज़्यादा जानने के लिए, इन संसाधनों को देखें:

सैंपल