राज्य को कहां जगाएं

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

सबसे सही तरीका

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

सबसे कम कॉमन ऐन्सेस्टर, कंपोज़िशन से बाहर भी हो सकता है. उदाहरण के लिए, ViewModel में स्थिति को हाइलाइट करते समय, कारोबारी नियम शामिल होता है.

इस पेज पर इस सबसे सही तरीके के बारे में विस्तार से बताया गया है और ध्यान रखने वाली एक चेतावनी दी गई है.

यूज़र इंटरफ़ेस (यूआई) की स्थिति और यूज़र इंटरफ़ेस (यूआई) लॉजिक के टाइप

यूज़र इंटरफ़ेस (यूआई) की स्थिति और इस्तेमाल किए जाने वाले लॉजिक की परिभाषाएं नीचे दी गई हैं पूरा दस्तावेज़ पढ़ें.

यूज़र इंटरफ़ेस (यूआई) की स्थिति

यूज़र इंटरफ़ेस (यूआई) की स्थिति वह प्रॉपर्टी है जो यूज़र इंटरफ़ेस (यूआई) की जानकारी देती है. यूज़र इंटरफ़ेस (यूआई) दो तरह के होते हैं राज्य:

  • स्क्रीन के यूज़र इंटरफ़ेस (यूआई) की स्थिति: इसका मतलब है कि आपको स्क्रीन पर क्या दिखाना है. उदाहरण के लिए, NewsUiState क्लास में ज़रूरी समाचार और अन्य जानकारी शामिल हो सकती है का इस्तेमाल करें. यह स्थिति आम तौर पर क्योंकि इसमें ऐप्लिकेशन का डेटा शामिल है.
  • यूज़र इंटरफ़ेस (यूआई) एलिमेंट की स्थिति, यूज़र इंटरफ़ेस (यूआई) एलिमेंट से जुड़ी प्रॉपर्टी के बारे में बताती है और उन्हें रेंडर करने के तरीके पर असर डाल सकते हैं. यूज़र इंटरफ़ेस (यूआई) एलिमेंट दिखाया या छिपाया जा सकता है और फ़ॉन्ट, साइज़ या फ़ॉन्ट के लिए एक तय रंग होना चाहिए. Android व्यू में, व्यू इस स्थिति को खुद प्रबंधित करती है, क्योंकि यह स्वाभाविक रूप से राज्य से जुड़ी होती है. साथ ही, इसकी स्थिति में बदलाव करें या उसके बारे में क्वेरी करें. उदाहरण के लिए, get और TextView क्लास के टेक्स्ट के लिए set तरीके. Jetpack में कंपोज़ेबल में कंपोज़ की गई स्थिति से बाहर का रास्ता होता है और उसे इधर-उधर ले जाया जा सकता है यह कॉम्पोनेंट, कंपोज़ेबल के आस-पास मौजूद नहीं है फ़ंक्शन या स्टेट होल्डर के रूप में दी जाती है. इसका एक उदाहरण ScaffoldState है, जिसमें Scaffold कंपोज़ेबल.

तर्क वाले गेम

किसी ऐप्लिकेशन में लॉजिक, बिज़नेस लॉजिक या यूज़र इंटरफ़ेस (यूआई) लॉजिक हो सकता है:

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

यूज़र इंटरफ़ेस (यूआई) लॉजिक

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

नीचे दोनों समाधानों का वर्णन दिया गया है और बताया गया है कि कब उपयोग करना चाहिए.

राज्य के मालिक के तौर पर कंपोज़ेबल

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

राज्य स्तर पर लिफ़्ट करने की ज़रूरत नहीं है

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

@Composable
fun ChatBubble(
    message: Message
) {
    var showDetails by rememberSaveable { mutableStateOf(false) } // Define the UI element expanded state

    ClickableText(
        text = AnnotatedString(message.content),
        onClick = { showDetails = !showDetails } // Apply simple UI logic
    )

    if (showDetails) {
        Text(message.timestamp)
    }
}

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

कंपोज़ेबल में रिकॉर्ड करना

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

नीचे दिए गए उदाहरण में, एक ऐसे चैट ऐप्लिकेशन का उदाहरण दिया गया है जिसमें ये दो सुविधाएं लागू की गई हैं:

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

कंपोज़ेबल हैरारकी इस तरह है:

चैट कंपोज़ेबल ट्री
दूसरी इमेज. चैट कंपोज़ेबल ट्री

LazyColumn की स्थिति को बातचीत वाली स्क्रीन पर ले जाया जाता है, ताकि ऐप्लिकेशन ये काम कर सके यूज़र इंटरफ़ेस (यूआई) लॉजिक का इस्तेमाल करें और उन सभी कंपोज़ेबल में स्टेटस को पढ़ें जिनके लिए इसकी ज़रूरत है:

LaZकॉलम से बातचीत स्क्रीन पर LazyColumn की स्थिति दिखाने का तरीका
तीसरी इमेज. LazyColumn स्थिति को LazyColumn से ConversationScreen पर ले जाया जा रहा है

इसलिए, कुल मिलाकर ये कंपोज़ेबल हैं:

लेज़ीलिस्टस्टेट के साथ चैट कंपोज़ेबल ट्री को ConversationScreen पर ले जाया गया
चौथी इमेज. LazyListState के साथ चैट कंपोज़ेबल ट्री, ConversationScreen पर पहुंच गया

कोड इस तरह से होता है:

@Composable
private fun ConversationScreen(/*...*/) {
    val scope = rememberCoroutineScope()

    val lazyListState = rememberLazyListState() // State hoisted to the ConversationScreen

    MessagesList(messages, lazyListState) // Reuse same state in MessageList

    UserInput(
        onMessageSent = { // Apply UI logic to lazyListState
            scope.launch {
                lazyListState.scrollToItem(0)
            }
        },
    )
}

@Composable
private fun MessagesList(
    messages: List<Message>,
    lazyListState: LazyListState = rememberLazyListState() // LazyListState has a default value
) {

    LazyColumn(
        state = lazyListState // Pass hoisted state to LazyColumn
    ) {
        items(messages, key = { message -> message.id }) { item ->
            Message(/*...*/)
        }
    }

    val scope = rememberCoroutineScope()

    JumpToBottom(onClicked = {
        scope.launch {
            lazyListState.scrollToItem(0) // UI logic being applied to lazyListState
        }
    })
}

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

ध्यान दें कि lazyListState को MessagesList तरीके में तय किया गया है. इसमें rememberLazyListState() की डिफ़ॉल्ट वैल्यू. यह Compose में आम तौर पर इस्तेमाल किया जाने वाला पैटर्न है. यह कंपोज़ेबल को फिर से इस्तेमाल करने लायक और सुविधाजनक बनाता है. इसके बाद, कंपोज़ेबल का इस्तेमाल किया जा सकता है अलग-अलग हिस्सों में किए जा सकते हैं, जिनके लिए शायद राज्य को कंट्रोल करने की ज़रूरत न पड़े. यह है यह आम तौर पर, कंपोज़ेबल की जांच या झलक देखते समय होता है. यह ठीक ऐसा ही है LazyColumn इसकी स्थिति के बारे में बताता है.

LazyListState के लिए सबसे कम कॉमन एंसेस्टर
पांचवीं इमेज. LazyListState के लिए सबसे कम कॉमन ऐन्सेस्टर ConversationScreen
है

राज्य के मालिक के तौर पर सामान्य राज्य धारक की क्लास

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

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

इन सामान्य क्लास को कंपोज़िशन में बनाया और याद रखा जाता है. क्योंकि वे कंपोज़ेबल के लाइफ़साइकल का पालन करता है, तो वे उससे जुड़े टाइप ले सकते हैं rememberNavController() या rememberLazyListState() जैसी लाइब्रेरी लिखें.

इसका एक उदाहरण LazyListState सादा राज्य का मालिक है क्लास, जिसे LazyColumn के यूज़र इंटरफ़ेस (यूआई) की जटिलता को कंट्रोल करने के लिए Compose में लागू किया गया है या LazyRow.

// LazyListState.kt

@Stable
class LazyListState constructor(
    firstVisibleItemIndex: Int = 0,
    firstVisibleItemScrollOffset: Int = 0
) : ScrollableState {
    /**
     *   The holder class for the current scroll position.
     */
    private val scrollPosition = LazyListScrollPosition(
        firstVisibleItemIndex, firstVisibleItemScrollOffset
    )

    suspend fun scrollToItem(/*...*/) { /*...*/ }

    override suspend fun scroll() { /*...*/ }

    suspend fun animateScrollToItem() { /*...*/ }
}

LazyListState, LazyColumn को स्टोर करने की स्थिति को एनकैप्सुलेट करता है इस यूज़र इंटरफ़ेस (यूआई) एलिमेंट के लिए scrollPosition. यह रिपोर्ट में बदलाव करने के दाईं ओर स्क्रोल करें.

जैसा कि आपको दिख रहा है, किसी कंपोज़ेबल की ज़िम्मेदारी बढ़ाने से स्टेट होल्डर की ज़रूरत है. ज़िम्मेदारियां, यूज़र इंटरफ़ेस (यूआई) लॉजिक में या सिर्फ़ राज्य की मात्रा का ट्रैक रखना.

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

बिज़नेस लॉजिक

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

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

राज्य के मालिक के तौर पर ViewModels

Android डेवलपमेंट में AAC ViewModels के फ़ायदे उन्हें सही बनाते हैं, जो बिज़नेस लॉजिक का ऐक्सेस देने और ऐप्लिकेशन का डेटा तैयार करने के लिए स्क्रीन पर प्रज़ेंटेशन के लिए.

ViewModel में यूज़र इंटरफ़ेस (यूआई) स्थिति को रखने पर, उसे कंपोज़िशन.

ViewModel पर फ़ेच किया गया स्टेट, कंपोज़िशन के बाहर सेव है.
छठी इमेज. ViewModel पर होस्ट किया गया राज्य, कंपोज़िशन के बाहर सेव है.

ViewModels, कंपोज़िशन के हिस्से के तौर पर सेव नहीं किए जाते. इन्हें पब्लिशर, फ़्रेमवर्क उपलब्ध कराया जाता है और उनका दायरा ViewModelStoreOwner तक सीमित होता है. यह नेविगेशन ग्राफ़ की गतिविधि, फ़्रैगमेंट, नेविगेशन ग्राफ़ या डेस्टिनेशन. इसके लिए ViewModel के दायरे के बारे में ज़्यादा जानकारी के लिए, दस्तावेज़ देखा जा सकता है.

इसके बाद, ViewModel सबसे सत्य और सबसे कम पूर्वज है यूज़र इंटरफ़ेस (यूआई) की स्थिति.

स्क्रीन यूज़र इंटरफ़ेस (यूआई) की स्थिति

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

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

class ConversationViewModel(
    channelId: String,
    messagesRepository: MessagesRepository
) : ViewModel() {

    val messages = messagesRepository
        .getLatestMessages(channelId)
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5_000),
            initialValue = emptyList()
        )

    // Business logic
    fun sendMessage(message: Message) { /* ... */ }
}

कंपोज़ेबल, ViewModel में लिफ़्ट की गई स्क्रीन के यूज़र इंटरफ़ेस (यूआई) की स्थिति का इस्तेमाल करते हैं. आपको ऐसा करना चाहिए स्क्रीन-लेवल के कंपोज़ेबल में ViewModel इंस्टेंस इंजेक्ट करें, ताकि कारोबारी नियम ऐक्सेस करने की सुविधा.

स्क्रीन-लेवल कंपोज़ेबल में इस्तेमाल किए गए ViewModel का उदाहरण नीचे दिया गया है. यहां कंपोज़ेबल ConversationScreen(), लिफ़्ट की गई स्क्रीन के यूज़र इंटरफ़ेस (यूआई) स्थिति का इस्तेमाल करता है ViewModel में:

@Composable
private fun ConversationScreen(
    conversationViewModel: ConversationViewModel = viewModel()
) {

    val messages by conversationViewModel.messages.collectAsStateWithLifecycle()

    ConversationScreen(
        messages = messages,
        onSendMessage = { message: Message -> conversationViewModel.sendMessage(message) }
    )
}

@Composable
private fun ConversationScreen(
    messages: List<Message>,
    onSendMessage: (Message) -> Unit
) {

    MessagesList(messages, onSendMessage)
    /* ... */
}

प्रॉपर्टी ड्रिलिंग

“प्रॉपर्टी की ड्रिलिंग” का मतलब है, नेस्ट किए गए कई चाइल्ड पब्लिशर के डेटा को एक जगह से दूसरी जगह भेजना कॉम्पोनेंट को पढ़ें.

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

हालांकि, इवेंट को अलग-अलग Lambda पैरामीटर के तौर पर दिखाने पर, फ़ंक्शन सिग्नेचर के साथ, इससे कंपोज़ेबल फ़ंक्शन को ज़्यादा से ज़्यादा लोगों को दिखाया जाता है ये ज़िम्मेदारी हैं. एक नज़र में देखा जा सकता है कि यह क्या करता है.

एनकैप्सुलेट के लिए रैपर क्लास बनाने की तुलना में प्रॉपर्टी ड्रिलिंग बेहतर है में एक ही जगह पर होने की वजह से, ज़िम्मेदारियां पूरी होती हैं. रैपर क्लास न होने से आपको और भी फ़ायदे मिलते हैं इस बात की संभावना है कि कंपोज़ेबल को सिर्फ़ अपने लिए ज़रूरी पैरामीटर पास किए जाएं, जो कि सबसे बढ़िया प्रैक्टिस करें.

अगर ये इवेंट नेविगेशन इवेंट हैं, तो भी सबसे सही यही तरीका लागू होता है. इसके बारे में ज़्यादा जानने के लिए, नेविगेशन वाले दस्तावेज़ देखें.

अगर आपने परफ़ॉर्मेंस से जुड़ी किसी समस्या का पता लगाया है, तो आपके पास पढ़ने को रोकने का विकल्प भी है राज्य का है. ज़्यादा जानने के लिए, परफ़ॉर्मेंस दस्तावेज़ देखें.

यूज़र इंटरफ़ेस (यूआई) एलिमेंट की स्थिति

अगर स्क्रीन लेवल की स्थिति मौजूद है, तो यूआई एलिमेंट की स्थिति को स्क्रीन पर दिखाया जा सकता है बिज़नेस लॉजिक जिसे उसे पढ़ने या लिखने की ज़रूरत होती है.

चैट ऐप्लिकेशन के उदाहरण में, ऐप्लिकेशन उपयोगकर्ता के सुझाव ग्रुप चैट, जब उपयोगकर्ता @ टाइप करता है और संकेत देता है. ये सुझाव डेटा लेयर और उपयोगकर्ता के सुझावों की सूची को कैलकुलेट करने के लॉजिक को ध्यान में रखा जाता है कारोबारी नियम. सुविधा इस तरह दिखती है:

यह सुविधा, जब उपयोगकर्ता `@` और संकेत टाइप करता है, तो ग्रुप चैट में उपयोगकर्ता के सुझाव दिखाती है
सातवीं इमेज. यह सुविधा, जब उपयोगकर्ता @ टाइप करता है और कोई संकेत टाइप करता है, तो ग्रुप चैट में सुझाव दिखाए जाते हैं

इस सुविधा को लागू करने वाला ViewModel ऐसा दिखेगा:

class ConversationViewModel(/*...*/) : ViewModel() {

    // Hoisted state
    var inputMessage by mutableStateOf("")
        private set

    val suggestions: StateFlow<List<Suggestion>> =
        snapshotFlow { inputMessage }
            .filter { hasSocialHandleHint(it) }
            .mapLatest { getHandle(it) }
            .mapLatest { repository.getSuggestions(it) }
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(5_000),
                initialValue = emptyList()
            )

    fun updateInput(newInput: String) {
        inputMessage = newInput
    }
}

inputMessage एक वैरिएबल है, जो TextField स्थिति को स्टोर करता है. हर बार नए इनपुट में उपयोगकर्ता टाइप का इस्तेमाल करते हैं, तो ऐप्लिकेशन suggestions बनाने के लिए बिज़नेस लॉजिक का इस्तेमाल करता है.

suggestions, स्क्रीन के यूज़र इंटरफ़ेस (यूआई) की स्थिति है और इसे 'लिखें' यूज़र इंटरफ़ेस (यूआई) में इस्तेमाल किया जा सकता है. इसके लिए, जानकारी इकट्ठा करें StateFlow से.

चेतावनी

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

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

हालांकि, DrawerState के close() तरीके को कॉल करने के लिए, viewModelScope 'लिखें' यूज़र इंटरफ़ेस (यूआई) की वजह से, रनटाइम के दौरान टाइप का अपवाद होता है IllegalStateException जिसमें “a” मैसेज लिखा है MonotonicFrameClock इसमें उपलब्ध नहीं है CoroutineContext”.

इसे ठीक करने के लिए, कंपोज़िशन के CoroutineScope के स्कोप का इस्तेमाल करें. यह CoroutineContext में MonotonicFrameClock, जो सस्पेंड फ़ंक्शन को काम पर ले जाता है.

इस क्रैश को ठीक करने के लिए, कोरूटीन के CoroutineContext को ViewModel से लेकर कंपोज़िशन के दायरे में. यह ऐसा दिख सकता है:

class ConversationViewModel(/*...*/) : ViewModel() {

    val drawerState = DrawerState(initialValue = DrawerValue.Closed)

    private val _drawerContent = MutableStateFlow(DrawerContent.Empty)
    val drawerContent: StateFlow<DrawerContent> = _drawerContent.asStateFlow()

    fun closeDrawer(uiScope: CoroutineScope) {
        viewModelScope.launch {
            withContext(uiScope.coroutineContext) { // Use instead of the default context
                drawerState.close()
            }
            // Fetch drawer content and update state
            _drawerContent.update { content }
        }
    }
}

// in Compose
@Composable
private fun ConversationScreen(
    conversationViewModel: ConversationViewModel = viewModel()
) {
    val scope = rememberCoroutineScope()

    ConversationScreen(onCloseDrawer = { conversationViewModel.closeDrawer(uiScope = scope) })
}

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

राज्य और Jetpack Compose के बारे में ज़्यादा जानने के लिए, ये देखें अतिरिक्त संसाधन शामिल करें.

सैंपल

कोड लैब

वीडियो