यूज़र इंटरफ़ेस (यूआई) इवेंट

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

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

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

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

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

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

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

उपयोगकर्ता के इवेंट मैनेज करना

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

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

व्यू

class LatestNewsActivity : AppCompatActivity() {

    private lateinit var binding: ActivityLatestNewsBinding
    private val viewModel: LatestNewsViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        /* ... */

        // The expand details event is processed by the UI that
        // modifies a View's internal state.
        binding.expandButton.setOnClickListener {
            binding.expandedSection.visibility = View.VISIBLE
        }

        // The refresh event is processed by the ViewModel that is in charge
        // of the business logic.
        binding.refreshButton.setOnClickListener {
            viewModel.refreshNews()
        }
    }
}

Compose

@Composable
fun LatestNewsScreen(viewModel: LatestNewsViewModel = viewModel()) {

    // State of whether more details should be shown
    var expanded by remember { mutableStateOf(false) }

    Column {
        Text("Some text")
        if (expanded) {
            Text("More details")
        }

        Button(
          // The expand details event is processed by the UI that
          // modifies this composable's internal state.
          onClick = { expanded = !expanded }
        ) {
          val expandText = if (expanded) "Collapse" else "Expand"
          Text("$expandText details")
        }

        // The refresh event is processed by the ViewModel that is in charge
        // of the UI's business logic.
        Button(onClick = { viewModel.refreshNews() }) {
            Text("Refresh data")
        }
    }
}

RecyclerViews में उपयोगकर्ता इवेंट

अगर कार्रवाई को यूज़र इंटरफ़ेस ट्री में नीचे की ओर किया जाता है, जैसे कि RecyclerView में आइटम या कस्टम View, ViewModel अब भी हैंडलिंग उपयोगकर्ता होना चाहिए इवेंट.

उदाहरण के लिए, मान लीजिए कि NewsActivity से सभी समाचार आइटम में एक बुकमार्क है बटन. ViewModel को बुकमार्क किए गए समाचार आइटम का आईडी जानने की ज़रूरत है. टास्क कब शुरू होगा जब उपयोगकर्ता किसी समाचार आइटम को बुकमार्क करता है, तो RecyclerView अडैप्टर ViewModel से addBookmark(newsId) फ़ंक्शन दिखाया गया, इसके लिए यह ज़रूरी है ViewModel पर निर्भर है. इसके बजाय, ViewModel एक स्टेट ऑब्जेक्ट दिखाता है जिसे NewsItemUiState कहा जाता है, जिसमें इवेंट:

data class NewsItemUiState(
    val title: String,
    val body: String,
    val bookmarked: Boolean = false,
    val publicationDate: String,
    val onBookmark: () -> Unit
)

class LatestNewsViewModel(
    private val formatDateUseCase: FormatDateUseCase,
    private val repository: NewsRepository
)
    val newsListUiItems = repository.latestNews.map { news ->
        NewsItemUiState(
            title = news.title,
            body = news.body,
            bookmarked = news.bookmarked,
            publicationDate = formatDateUseCase(news.publicationDate),
            // Business logic is passed as a lambda function that the
            // UI calls on click events.
            onBookmark = {
                repository.addBookmark(news.id)
            }
        )
    }
}

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

उपयोगकर्ता इवेंट फ़ंक्शन के लिए नाम रखने के तरीके

इस गाइड में, उपयोगकर्ता इवेंट को मैनेज करने वाले ViewModel फ़ंक्शन के नाम कार्रवाई के आधार पर कार्रवाई की गई है. उदाहरण के लिए: addBookmark(id) या logIn(username, password).

ViewModel इवेंट मैनेज करना

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

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

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

data class LoginUiState(
    val isLoading: Boolean = false,
    val errorMessage: String? = null,
    val isUserLoggedIn: Boolean = false
)

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

व्यू

class LoginViewModel : ViewModel() {
    private val _uiState = MutableStateFlow(LoginUiState())
    val uiState: StateFlow<LoginUiState> = _uiState.asStateFlow()
    /* ... */
}

class LoginActivity : AppCompatActivity() {
    private val viewModel: LoginViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        /* ... */

        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect { uiState ->
                    if (uiState.isUserLoggedIn) {
                        // Navigate to the Home screen.
                    }
                    ...
                }
            }
        }
    }
}

Compose

class LoginViewModel : ViewModel() {
    var uiState by mutableStateOf(LoginUiState())
        private set
    /* ... */
}

@Composable
fun LoginScreen(
    viewModel: LoginViewModel = viewModel(),
    onUserLogIn: () -> Unit
) {
    val currentOnUserLogIn by rememberUpdatedState(onUserLogIn)

    // Whenever the uiState changes, check if the user is logged in.
    LaunchedEffect(viewModel.uiState)  {
        if (viewModel.uiState.isUserLoggedIn) {
            currentOnUserLogIn()
        }
    }

    // Rest of the UI for the login screen.
}

इवेंट इस्तेमाल करने से स्थिति के अपडेट ट्रिगर हो सकते हैं

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

// Models the UI state for the Latest news screen.
data class LatestNewsUiState(
    val news: List<News> = emptyList(),
    val isLoading: Boolean = false,
    val userMessage: String? = null
)

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

व्यू

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

    private val _uiState = MutableStateFlow(LatestNewsUiState(isLoading = true))
    val uiState: StateFlow<LatestNewsUiState> = _uiState

    fun refreshNews() {
        viewModelScope.launch {
            // If there isn't internet connection, show a new message on the screen.
            if (!internetConnection()) {
                _uiState.update { currentUiState ->
                    currentUiState.copy(userMessage = "No Internet connection")
                }
                return@launch
            }

            // Do something else.
        }
    }

    fun userMessageShown() {
        _uiState.update { currentUiState ->
            currentUiState.copy(userMessage = null)
        }
    }
}

Compose

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

    var uiState by mutableStateOf(LatestNewsUiState())
        private set

    fun refreshNews() {
        viewModelScope.launch {
            // If there isn't internet connection, show a new message on the screen.
            if (!internetConnection()) {
                uiState = uiState.copy(userMessage = "No Internet connection")
                return@launch
            }

            // Do something else.
        }
    }

    fun userMessageShown() {
        uiState = uiState.copy(userMessage = null)
    }
}

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

व्यू

class LatestNewsActivity : AppCompatActivity() {
    private val viewModel: LatestNewsViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        /* ... */

        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect { uiState ->
                    uiState.userMessage?.let {
                        // TODO: Show Snackbar with userMessage.

                        // Once the message is displayed and
                        // dismissed, notify the ViewModel.
                        viewModel.userMessageShown()
                    }
                    ...
                }
            }
        }
    }
}

Compose

@Composable
fun LatestNewsScreen(
    snackbarHostState: SnackbarHostState,
    viewModel: LatestNewsViewModel = viewModel(),
) {
    // Rest of the UI content.

    // If there are user messages to show on the screen,
    // show it and notify the ViewModel.
    viewModel.uiState.userMessage?.let { userMessage ->
        LaunchedEffect(userMessage) {
            snackbarHostState.showSnackbar(userMessage)
            // Once the message is displayed and dismissed, notify the ViewModel.
            viewModel.userMessageShown()
        }
    }
}

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

इवेंट का इस्तेमाल करने से, राज्य के बारे में अपडेट ट्रिगर हो सकते हैं सेक्शन में बताया गया है कि स्क्रीन. नेविगेशन इवेंट, Android ऐप्लिकेशन में होने वाले एक तरह के इवेंट भी हैं.

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

व्यू

class LoginActivity : AppCompatActivity() {

    private lateinit var binding: ActivityLoginBinding
    private val viewModel: LoginViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        /* ... */

        binding.helpButton.setOnClickListener {
            navController.navigate(...) // Open help screen
        }
    }
}

Compose

@Composable
fun LoginScreen(
    onHelp: () -> Unit, // Caller navigates to the right screen
    viewModel: LoginViewModel = viewModel()
) {
    // Rest of the UI

    Button(onClick = onHelp) {
        Text("Get help")
    }
}

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

व्यू

class LoginActivity : AppCompatActivity() {
    private val viewModel: LoginViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        /* ... */

        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect { uiState ->
                    if (uiState.isUserLoggedIn) {
                        // Navigate to the Home screen.
                    }
                    ...
                }
            }
        }
    }
}

Compose

@Composable
fun LoginScreen(
    onUserLogIn: () -> Unit, // Caller navigates to the right screen
    viewModel: LoginViewModel = viewModel()
) {
    Button(
        onClick = {
            // ViewModel validation is triggered
            viewModel.login()
        }
    ) {
        Text("Log in")
    }
    // Rest of the UI

    val lifecycle = LocalLifecycleOwner.current.lifecycle
    val currentOnUserLogIn by rememberUpdatedState(onUserLogIn)
    LaunchedEffect(viewModel, lifecycle)  {
        // Whenever the uiState changes, check if the user is logged in and
        // call the `onUserLogin` event when `lifecycle` is at least STARTED
        snapshotFlow { viewModel.uiState }
            .filter { it.isUserLoggedIn }
            .flowWithLifecycle(lifecycle)
            .collect {
                currentOnUserLogIn()
            }
    }
}

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

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

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

व्यू

// Key that identifies the `validationInProgress` state in the Bundle
private const val DOB_VALIDATION_KEY = "dobValidationKey"

class DobValidationFragment : Fragment() {

    private var validationInProgress: Boolean = false
    private val viewModel: DobValidationViewModel by viewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val binding = // ...
        validationInProgress = savedInstanceState?.getBoolean(DOB_VALIDATION_KEY) ?: false

        binding.continueButton.setOnClickListener {
            viewModel.validateDob()
            validationInProgress = true
        }

        viewLifecycleOwner.lifecycleScope.launch {
            viewModel.uiState
                .flowWithLifecycle(viewLifecycleOwner.lifecycle)
                .collect { uiState ->
                    // Update other parts of the UI ...

                    // If the input is valid and the user wants
                    // to navigate, navigate to the next screen
                    // and reset `validationInProgress` flag
                    if (uiState.isDobValid && validationInProgress) {
                        validationInProgress = false
                        navController.navigate(...) // Navigate to next screen
                    }
                }
        }

        return binding
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putBoolean(DOB_VALIDATION_KEY, validationInProgress)
    }
}

Compose

class DobValidationViewModel(/* ... */) : ViewModel() {
    var uiState by mutableStateOf(DobValidationUiState())
        private set
}

@Composable
fun DobValidationScreen(
    onNavigateToNextScreen: () -> Unit, // Caller navigates to the right screen
    viewModel: DobValidationViewModel = viewModel()
) {
    // TextField that updates the ViewModel when a date of birth is selected

    var validationInProgress by rememberSaveable { mutableStateOf(false) }

    Button(
        onClick = {
            viewModel.validateInput()
            validationInProgress = true
        }
    ) {
        Text("Continue")
    }
    // Rest of the UI

    /*
     * The following code implements the requirement of advancing automatically
     * to the next screen when a valid date of birth has been introduced
     * and the user wanted to continue with the registration process.
     */

    if (validationInProgress) {
        val lifecycle = LocalLifecycleOwner.current.lifecycle
        val currentNavigateToNextScreen by rememberUpdatedState(onNavigateToNextScreen)
        LaunchedEffect(viewModel, lifecycle) {
            // If the date of birth is valid and the validation is in progress,
            // navigate to the next screen when `lifecycle` is at least STARTED,
            // which is the default Lifecycle.State for the `flowWithLifecycle` operator.
            snapshotFlow { viewModel.uiState }
                .filter { it.isDobValid }
                .flowWithLifecycle(lifecycle)
                .collect {
                    validationInProgress = false
                    currentNavigateToNextScreen()
                }
        }
    }
}

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

इस्तेमाल के अन्य उदाहरण

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

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

सैंपल

नीचे दिए गए Google सैंपल, यूज़र इंटरफ़ेस (यूआई) लेयर. इस दिशा-निर्देश को देखने के लिए, उन्हें एक्सप्लोर करें: