Compose में बुरा असर

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

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

स्थिति और असर के इस्तेमाल के उदाहरण

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

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

LaunchedEffect: कंपोज़ेबल के स्कोप में सस्पेंड फ़ंक्शन को रन करें

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

उदाहरण के लिए, यहां एक ऐनिमेशन दिया गया है, जो कॉन्फ़िगर करने में देरी:

// Allow the pulse rate to be configured, so it can be sped up if the user is running
// out of time
var pulseRateMs by remember { mutableStateOf(3000L) }
val alpha = remember { Animatable(1f) }
LaunchedEffect(pulseRateMs) { // Restart the effect when the pulse rate changes
    while (isActive) {
        delay(pulseRateMs) // Pulse the alpha every pulseRateMs to alert the user
        alpha.animateTo(0f)
        alpha.animateTo(1f)
    }
}

ऊपर दिए गए कोड में, ऐनिमेशन निलंबन फ़ंक्शन का इस्तेमाल करता है delay ताकि समय की तय सीमा तक इंतज़ार किया जा सके. इसके बाद, यह क्रम के हिसाब से ऐल्फ़ा का ऐनिमेशन दिखाता है और फिर से animateTo. यह कंपोज़ेबल के पूरे जीवनकाल के दौरान दोहराया जाएगा.

rememberCoroutineScope: कंपोज़ेबल के बाहर कोरूटीन लॉन्च करने के लिए, कंपोज़िशन की जानकारी का स्कोप पाएं

LaunchedEffect एक कंपोज़ेबल फ़ंक्शन है, इसलिए इसका इस्तेमाल सिर्फ़ अन्य कंपोज़ेबल फ़ंक्शन का इस्तेमाल किया जा सकता है. किसी कंपोज़ेबल के बाहर कोरूटीन लॉन्च करने के लिए, का दायरा इस तरह तय किया जाता है कि प्रॉपर्टी के बाहर निकलने पर, वह अपने-आप रद्द हो जाएगा कंपोज़िशन, इस्तेमाल rememberCoroutineScope. साथ ही, जब भी आपको इसकी लाइफ़साइकल कंट्रोल करनी हो, तब rememberCoroutineScope का इस्तेमाल करें एक या एक से ज़्यादा कोरूटीन को मैन्युअल तौर पर सेट किया जाता है. उदाहरण के लिए, किसी ऐनिमेशन को रद्द करने पर उपयोगकर्ता इवेंट होता है.

rememberCoroutineScope एक कंपोज़ेबल फ़ंक्शन है, जो CoroutineScope कंपोज़िशन के पॉइंट से जुड़ा हुआ है जहां इसे कहा जाता है. कॉन्टेंट बनाने कॉल कंपोज़िशन छोड़ने पर, दायरा रद्द हो जाएगा.

पिछले उदाहरण के अनुसार, आप Snackbar दिखाने के लिए इस कोड का उपयोग कर सकते हैं जब उपयोगकर्ता किसी Button पर टैप करता है:

@Composable
fun MoviesScreen(snackbarHostState: SnackbarHostState) {

    // Creates a CoroutineScope bound to the MoviesScreen's lifecycle
    val scope = rememberCoroutineScope()

    Scaffold(
        snackbarHost = {
            SnackbarHost(hostState = snackbarHostState)
        }
    ) { contentPadding ->
        Column(Modifier.padding(contentPadding)) {
            Button(
                onClick = {
                    // Create a new coroutine in the event handler to show a snackbar
                    scope.launch {
                        snackbarHostState.showSnackbar("Something happened!")
                    }
                }
            ) {
                Text("Press me")
            }
        }
    }
}

rememberUpdatedState: इफ़ेक्ट में ऐसी वैल्यू का रेफ़रंस दें जो वैल्यू बदलने पर रीस्टार्ट न हो

किसी एक मुख्य पैरामीटर में बदलाव होने पर, LaunchedEffect रीस्टार्ट होता है. हालांकि, कुछ परिस्थितियों में आप अपने प्रभाव में एक मान कैप्चर करना चाहेंगे, जो कि बदलाव नहीं करते हैं, तो आप प्रभाव को पुनः शुरू नहीं करना चाहते. ऐसा करने के लिए, आपको इस वैल्यू का रेफ़रंस बनाने के लिए, rememberUpdatedState का इस्तेमाल करना ज़रूरी है उन्हें कैप्चर और अपडेट किया जा सकता है. यह तरीका उन इफ़ेक्ट के लिए मददगार है जिनमें ये चीज़ें शामिल हैं लंबे समय तक चलने वाले ऐसे ऑपरेशन जिन्हें फिर से बनाना महंगा या मुश्किल हो सकता है और रीस्टार्ट करें.

उदाहरण के लिए, मान लें कि आपके ऐप्लिकेशन में ऐसा LandingScreen है जो कुछ समय बाद गायब हो जाता है समय. भले ही LandingScreen को फिर से शामिल किया गया हो, लेकिन इसका असर कुछ समय तक इंतज़ार करता है और सूचित करता है कि बीत चुके समय को रीस्टार्ट नहीं किया जाना चाहिए:

@Composable
fun LandingScreen(onTimeout: () -> Unit) {

    // This will always refer to the latest onTimeout function that
    // LandingScreen was recomposed with
    val currentOnTimeout by rememberUpdatedState(onTimeout)

    // Create an effect that matches the lifecycle of LandingScreen.
    // If LandingScreen recomposes, the delay shouldn't start again.
    LaunchedEffect(true) {
        delay(SplashWaitTimeMillis)
        currentOnTimeout()
    }

    /* Landing screen content */
}

कॉल साइट की लाइफ़साइकल से मेल खाने वाला इफ़ेक्ट बनाने के लिए, कभी न बदलने वाला कॉन्सटेंट Unit या true, पैरामीटर के तौर पर पास किया जाता है. इस ऊपर दिए गए कोड, LaunchedEffect(true) का इस्तेमाल किया गया है. यह पक्का करने के लिए कि onTimeout लैम्डा हमेशा में वह नई वैल्यू शामिल होती है जिसे LandingScreen को फिर से शामिल किया गया था इसके साथ, onTimeout को rememberUpdatedState फ़ंक्शन के साथ रैप किया जाना चाहिए. कोड में लौटाए गए State, currentOnTimeout का इस्तेमाल इसमें किया जाना चाहिए इफ़ेक्ट.

DisposableEffect: ऐसे इफ़ेक्ट जिन्हें क्लीनअप की ज़रूरत होती है

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

उदाहरण के लिए, हो सकता है कि आप इसके आधार पर Analytics इवेंट भेजना चाहें Lifecycle इवेंट और पासवर्ड का इस्तेमाल करके LifecycleObserver. उन इवेंट को Compose में सुनने के लिए, DisposableEffect का इस्तेमाल करके रजिस्टर करें और ज़रूरत पड़ने पर ऑब्ज़र्वर का रजिस्ट्रेशन रद्द करें.

@Composable
fun HomeScreen(
    lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
    onStart: () -> Unit, // Send the 'started' analytics event
    onStop: () -> Unit // Send the 'stopped' analytics event
) {
    // Safely update the current lambdas when a new one is provided
    val currentOnStart by rememberUpdatedState(onStart)
    val currentOnStop by rememberUpdatedState(onStop)

    // If `lifecycleOwner` changes, dispose and reset the effect
    DisposableEffect(lifecycleOwner) {
        // Create an observer that triggers our remembered callbacks
        // for sending analytics events
        val observer = LifecycleEventObserver { _, event ->
            if (event == Lifecycle.Event.ON_START) {
                currentOnStart()
            } else if (event == Lifecycle.Event.ON_STOP) {
                currentOnStop()
            }
        }

        // Add the observer to the lifecycle
        lifecycleOwner.lifecycle.addObserver(observer)

        // When the effect leaves the Composition, remove the observer
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(observer)
        }
    }

    /* Home screen content */
}

ऊपर दिए गए कोड में, यह प्रभाव observer को lifecycleOwner. अगर lifecycleOwner में बदलाव होता है, तो इफ़ेक्ट हटा दिया जाता है और lifecycleOwner के साथ रीस्टार्ट किया गया.

DisposableEffect में आखिरी स्टेटमेंट के तौर पर onDispose क्लॉज़ शामिल होना चाहिए अपने कोड के ब्लॉक में. ऐसा न करने पर, IDE में बिल्ड-टाइम की गड़बड़ी दिखती है.

SideEffect: लिखें स्थिति को गैर-लिखें कोड में प्रकाशित करें

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

उदाहरण के लिए, आंकड़ों की लाइब्रेरी आपको अपने उपयोगकर्ता को कस्टम मेटाडेटा (इस उदाहरण में "उपयोगकर्ता प्रॉपर्टी") अटैच करके जनसंख्या Analytics के सभी इवेंट का डेटा इकट्ठा करने में मदद मिलती है. यह बताने के लिए कि उपयोगकर्ता मौजूदा उपयोगकर्ता को Analytics लाइब्रेरी में जोड़ा है, तो इसकी वैल्यू अपडेट करने के लिए SideEffect का इस्तेमाल करें.

@Composable
fun rememberFirebaseAnalytics(user: User): FirebaseAnalytics {
    val analytics: FirebaseAnalytics = remember {
        FirebaseAnalytics()
    }

    // On every successful composition, update FirebaseAnalytics with
    // the userType from the current User, ensuring that future analytics
    // events have this metadata attached
    SideEffect {
        analytics.setUserProperty("userType", user.userType)
    }
    return analytics
}

produceState: गैर-लिखें स्थिति को लिखें स्थिति में बदलें

produceState कंपोज़िशन के लिए एक कोरूटीन स्कोप लॉन्च करता है, जो वैल्यू को State लौटाया गया. इसका इस्तेमाल इन कामों के लिए करें गैर-लिखें स्थिति को लिखें स्थिति में बदलें, उदाहरण के लिए बाहरी सदस्यता-आधारित स्थिति जैसे कि Flow, LiveData, या RxJava कंपोज़िशन.

produceState के कंपोज़िशन में शामिल होने के बाद, निर्माता लॉन्च हो जाएगा और कंपोज़िशन छोड़ने पर रद्द हो जाता है. लौटाया गया State, एक-दूसरे से मेल खा रहा है; उसी वैल्यू को सेट करने से, बदलाव को ट्रिगर नहीं किया जाएगा.

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

नीचे दिया गया उदाहरण, produceState का इस्तेमाल करके नेटवर्क. loadNetworkImage कंपोज़ेबल फ़ंक्शन, State दिखाता है जो अन्य कंपोज़ेबल में इस्तेमाल किया जा सकता है.

@Composable
fun loadNetworkImage(
    url: String,
    imageRepository: ImageRepository = ImageRepository()
): State<Result<Image>> {

    // Creates a State<T> with Result.Loading as initial value
    // If either `url` or `imageRepository` changes, the running producer
    // will cancel and will be re-launched with the new inputs.
    return produceState<Result<Image>>(initialValue = Result.Loading, url, imageRepository) {

        // In a coroutine, can make suspend calls
        val image = imageRepository.load(url)

        // Update State with either an Error or Success result.
        // This will trigger a recomposition where this State is read
        value = if (image == null) {
            Result.Error
        } else {
            Result.Success(image)
        }
    }
}

derivedStateOf: एक या एक से ज़्यादा स्थिति वाले ऑब्जेक्ट को दूसरी स्थिति में बदलें

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

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

सही इस्तेमाल

नीचे दिया गया स्निपेट, derivedStateOf के इस्तेमाल का सही उदाहरण दिखाता है:

@Composable
// When the messages parameter changes, the MessageList
// composable recomposes. derivedStateOf does not
// affect this recomposition.
fun MessageList(messages: List<Message>) {
    Box {
        val listState = rememberLazyListState()

        LazyColumn(state = listState) {
            // ...
        }

        // Show the button if the first visible item is past
        // the first item. We use a remembered derived state to
        // minimize unnecessary compositions
        val showButton by remember {
            derivedStateOf {
                listState.firstVisibleItemIndex > 0
            }
        }

        AnimatedVisibility(visible = showButton) {
            ScrollToTopButton()
        }
    }
}

इस स्निपेट में, जब भी पहला दिखाई देने वाला आइटम firstVisibleItemIndex बदलता है बदलाव. स्क्रोल करने पर वैल्यू 0, 1, 2, 3, 4, 5 वगैरह हो जाती है. हालांकि, दोबारा कॉम्पोनेंट बनाने की ज़रूरत सिर्फ़ तब होती है, जब वैल्यू 0 से ज़्यादा हो. अपडेट की फ़्रीक्वेंसी में अंतर होने का मतलब है कि यह इन मामलों में बेहतर है derivedStateOf.

गलत इस्तेमाल

यह मानकर चलना की एक आम गलती यह है कि जब दो Compose की स्थिति वाले ऑब्जेक्ट को जोड़ा जाता है, आपको derivedStateOf का इस्तेमाल करना चाहिए, क्योंकि आपकी "शुरुआत की स्थिति" है. हालांकि, इस पूरी तरह से ओवरहेड होता है और इसकी ज़रूरत नहीं होती, जैसा कि इस स्निपेट में दिखाया गया है:

// DO NOT USE. Incorrect usage of derivedStateOf.
var firstName by remember { mutableStateOf("") }
var lastName by remember { mutableStateOf("") }

val fullNameBad by remember { derivedStateOf { "$firstName $lastName" } } // This is bad!!!
val fullNameCorrect = "$firstName $lastName" // This is correct

इस स्निपेट में, fullName को उतनी बार अपडेट करना होगा जितनी बार firstName और lastName. इसलिए, कोई अतिरिक्त रीकंपोज़िशन नहीं हो रही है और इसका इस्तेमाल derivedStateOf आवश्यक नहीं है.

snapshotFlow: कंपोज़ की स्थिति को फ़्लो में बदलें

snapshotFlow का इस्तेमाल करें State<T> का फ़ॉर्मैट बदलने के लिए चीज़ों को ठंडे प्रवाह में ले जाएं. इकट्ठा किए जाने और उत्सर्जन होने पर snapshotFlow अपने ब्लॉक को ट्रिगर करता है उसमें पढ़े गए State ऑब्जेक्ट का नतीजा मिलेगा. जब State ऑब्जेक्ट में से कोई एक snapshotFlow ब्लॉक म्यूटेट के अंदर पढ़ें, फ़्लो नई वैल्यू को छोड़ देगा अपने कलेक्टर में तब जोड़ेगा, जब नई वैल्यू इसके बराबर न हो पिछला उत्सर्जित मान (यह व्यवहार इसके समान है Flow.distinctUntilChanged).

यहां दिए गए उदाहरण में, उपयोगकर्ता के स्क्रोल करने पर रिकॉर्ड होने वाला खराब असर दिखाया गया है Analytics में सूची का पहला आइटम चिपकाएं:

val listState = rememberLazyListState()

LazyColumn(state = listState) {
    // ...
}

LaunchedEffect(listState) {
    snapshotFlow { listState.firstVisibleItemIndex }
        .map { index -> index > 0 }
        .distinctUntilChanged()
        .filter { it == true }
        .collect {
            MyAnalyticsService.sendScrolledPastFirstItemEvent()
        }
}

ऊपर दिए गए कोड में, listState.firstVisibleItemIndex को ऐसे फ़्लो में बदल दिया जाता है जो को फ़्लो के ऑपरेटर की ताकत का फ़ायदा मिल सकता है.

इफ़ेक्ट रीस्टार्ट किए जा रहे हैं

कंपोज़ की सुविधा में मौजूद कुछ इफ़ेक्ट, जैसे कि LaunchedEffect, produceState या DisposableEffect, आर्ग्युमेंट और कुंजियों का वैरिएबल नंबर लें जिनका इस्तेमाल इन कामों के लिए किया जाता है चल रहे इफ़ेक्ट को रद्द करें और नई कुंजियों के साथ नया इफ़ेक्ट शुरू करें.

इन एपीआई का सामान्य फ़ॉर्म यह है:

EffectName(restartIfThisKeyChanges, orThisKey, orThisKey, ...) { block }

इस व्यवहार की बारीकियों की वजह से, समस्याएं आ सकती हैं, अगर पैरामीटर का इस्तेमाल करके इफ़ेक्ट को फिर से शुरू किया जाता है, तो वह सही नहीं होता है:

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

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

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

@Composable
fun HomeScreen(
    lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
    onStart: () -> Unit, // Send the 'started' analytics event
    onStop: () -> Unit // Send the 'stopped' analytics event
) {
    // These values never change in Composition
    val currentOnStart by rememberUpdatedState(onStart)
    val currentOnStop by rememberUpdatedState(onStop)

    DisposableEffect(lifecycleOwner) {
        val observer = LifecycleEventObserver { _, event ->
            /* ... */
        }

        lifecycleOwner.lifecycle.addObserver(observer)
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(observer)
        }
    }
}

DisposableEffect के तौर पर currentOnStart और currentOnStop की ज़रूरत नहीं है कुंजियों की वजह से, कंपोज़िशन में उनकी वैल्यू कभी नहीं बदलती है. ऐसा इसलिए, क्योंकि rememberUpdatedState. अगर आप lifecycleOwner को पैरामीटर के रूप में पास नहीं करते हैं और यह बदल जाता है, HomeScreen फिर से हो जाता है, लेकिन DisposableEffect को नष्ट नहीं किया जाता है में से चुनें और रीस्टार्ट किया गया. इससे गड़बड़ी होती है, क्योंकि गलत lifecycleOwner उसके बाद से इस्तेमाल किया जा रहा है.

कॉन्स्टेंट को कुंजियों के रूप में

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