কম্পোজ এর পার্শ্বপ্রতিক্রিয়া

একটি পার্শ্ব-প্রতিক্রিয়া হল অ্যাপের অবস্থার পরিবর্তন যা একটি কম্পোজেবল ফাংশনের আওতার বাইরে ঘটে। কম্পোজেবলের জীবনচক্র এবং অপ্রত্যাশিত পুনর্গঠনের মতো বৈশিষ্ট্যের কারণে, বিভিন্ন ক্রমে কম্পোজেবলের পুনর্গঠন সম্পাদন করা, অথবা বাতিল করা যেতে পারে এমন পুনর্গঠনের কারণে, কম্পোজেবল আদর্শভাবে পার্শ্ব-প্রতিক্রিয়ামুক্ত হওয়া উচিত

তবে, কখনও কখনও পার্শ্ব প্রতিক্রিয়ার প্রয়োজন হয়, উদাহরণস্বরূপ, একটি একক ইভেন্ট ট্রিগার করার জন্য যেমন একটি স্ন্যাকবার দেখানো বা একটি নির্দিষ্ট অবস্থায় অন্য স্ক্রিনে নেভিগেট করার জন্য। এই ক্রিয়াগুলি একটি নিয়ন্ত্রিত পরিবেশ থেকে করা উচিত যা কম্পোজেবলের জীবনচক্র সম্পর্কে সচেতন। এই পৃষ্ঠায়, আপনি জেটপ্যাক কম্পোজের বিভিন্ন পার্শ্ব প্রতিক্রিয়া API সম্পর্কে জানতে পারবেন।

অবস্থা এবং প্রভাব ব্যবহারের ক্ষেত্রে

থিংকিং ইন কম্পোজ ডকুমেন্টেশনে বর্ণিত হিসাবে, কম্পোজেবলগুলি পার্শ্ব প্রতিক্রিয়ামুক্ত হওয়া উচিত। যখন আপনার অ্যাপের অবস্থা পরিবর্তন করার প্রয়োজন হয় ( ম্যানেজিং স্টেট ডকুমেন্টেশন ডকুমেন্টেশনে বর্ণিত), তখন আপনার Effect API গুলি ব্যবহার করা উচিত যাতে সেই পার্শ্ব প্রতিক্রিয়াগুলি পূর্বাভাসযোগ্যভাবে কার্যকর করা হয়

কম্পোজে বিভিন্ন সম্ভাবনার প্রভাব খোলার কারণে, এগুলি সহজেই অতিরিক্ত ব্যবহার করা যেতে পারে। নিশ্চিত করুন যে আপনি এগুলিতে যে কাজটি করেন তা UI সম্পর্কিত এবং Managing state documentation এ বর্ণিত একমুখী ডেটা প্রবাহকে ব্যাহত না করে।

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 { mutableLongStateOf(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 হল একটি কম্পোজেবল ফাংশন যা Composition এর সেই বিন্দুতে আবদ্ধ একটি CoroutineScope ফেরত পাঠায় যেখানে এটি কল করা হয়। Composition থেকে কলটি বেরিয়ে গেলে স্কোপটি বাতিল হয়ে যাবে।

পূর্ববর্তী উদাহরণ অনুসরণ করে, ব্যবহারকারী যখন একটি Button এ ট্যাপ করেন তখন আপনি একটি Snackbar দেখানোর জন্য এই কোডটি ব্যবহার করতে পারেন:

@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 কী পরিবর্তন হয়, তাহলে কম্পোজেবলকে তার বর্তমান প্রভাবটি নিষ্পত্তি করতে হবে (পরিষ্কার করতে হবে), এবং আবার প্রভাবটি কল করে পুনরায় সেট করতে হবে।

উদাহরণস্বরূপ, আপনি 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 */
}

উপরের কোডে, প্রভাবটি lifecycleOwnerobserver যুক্ত করবে। যদি lifecycleOwner পরিবর্তন হয়, তাহলে প্রভাবটি নিষ্পত্তি করা হবে এবং নতুন lifecycleOwner দিয়ে পুনরায় চালু করা হবে।

একটি DisposableEffect কোড ব্লকের চূড়ান্ত বিবৃতি হিসেবে একটি onDispose ধারা অন্তর্ভুক্ত করতে হবে। অন্যথায়, IDE একটি বিল্ড-টাইম ত্রুটি প্রদর্শন করবে।

SideEffect : কম্পোজ অবস্থাকে নন-রচনা কোডে প্রকাশ করুন

কম্পোজ দ্বারা পরিচালিত নয় এমন বস্তুর সাথে কম্পোজ অবস্থা ভাগ করতে, SideEffect composable ব্যবহার করুন। SideEffect ব্যবহার করলে প্রতিটি সফল পুনর্গঠনের পরে প্রভাব কার্যকর হবে তা নিশ্চিত করা হয়। অন্যদিকে, একটি সফল পুনর্গঠন নিশ্চিত হওয়ার আগে একটি প্রভাব সম্পাদন করা ভুল, যা সরাসরি একটি কম্পোজেবলে প্রভাব লেখার ক্ষেত্রে প্রযোজ্য।

উদাহরণস্বরূপ, আপনার অ্যানালিটিক্স লাইব্রেরি আপনাকে পরবর্তী সমস্ত অ্যানালিটিক্স ইভেন্টের সাথে কাস্টম মেটাডেটা ("এই উদাহরণে ব্যবহারকারীর বৈশিষ্ট্য") সংযুক্ত করে আপনার ব্যবহারকারীর সংখ্যা ভাগ করার অনুমতি দিতে পারে। আপনার অ্যানালিটিক্স লাইব্রেরিতে বর্তমান ব্যবহারকারীর ব্যবহারকারীর ধরণ যোগাযোগ করতে, এর মান আপডেট করতে 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 Composition-এ প্রবেশ করে তখন producer চালু হয় এবং Composition থেকে বেরিয়ে গেলে বাতিল হয়ে যায়। ফিরে আসা State একত্রিত হয়; একই মান সেট করলে পুনঃসংযোজন শুরু হবে না।

যদিও produceState একটি কোরোটিন তৈরি করে, এটি অ-সাসপেন্ডিং ডেটা উৎসগুলি পর্যবেক্ষণ করতেও ব্যবহার করা যেতে পারে। সেই উৎসের সাবস্ক্রিপশন অপসারণ করতে, awaitDispose ফাংশনটি ব্যবহার করুন।

নিচের উদাহরণে দেখানো হয়েছে কিভাবে produceState ব্যবহার করে নেটওয়ার্ক থেকে একটি ছবি লোড করতে হয়। loadNetworkImage composable ফাংশনটি এমন একটি State প্রদান করে যা অন্যান্য composables-এ ব্যবহার করা যেতে পারে।

@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 : এক বা একাধিক স্টেট অবজেক্টকে অন্য স্টেটে রূপান্তর করা

কম্পোজে, প্রতিবার যখন কোনও পর্যবেক্ষিত স্টেট অবজেক্ট বা কম্পোজেবল ইনপুট পরিবর্তন হয় তখনই রিকম্পোজিশন ঘটে। একটি স্টেট অবজেক্ট বা ইনপুট UI-এর আপডেটের চেয়ে বেশি ঘন ঘন পরিবর্তিত হতে পারে, যার ফলে অপ্রয়োজনীয় রিকম্পোজিশন হয়।

যখন কম্পোজেবলের ইনপুটগুলি আপনার প্রয়োজনের চেয়ে বেশি ঘন ঘন পরিবর্তিত হয়, তখন আপনার derivedStateOf ফাংশনটি ব্যবহার করা উচিত। এটি প্রায়শই ঘটে যখন কোনও কিছু ঘন ঘন পরিবর্তিত হয়, যেমন একটি স্ক্রোল অবস্থান, তবে কম্পোজেবলকে কেবল একটি নির্দিষ্ট থ্রেশহোল্ড অতিক্রম করার পরেই প্রতিক্রিয়া জানাতে হয়। derivedStateOf একটি নতুন কম্পোজ স্টেট অবজেক্ট তৈরি করে যা আপনি পর্যবেক্ষণ করতে পারেন এবং যতটা প্রয়োজন ততটাই আপডেট হয়। এইভাবে, এটি Kotlin Flows 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 state অবজেক্ট একত্রিত করেন, তখন আপনার derivedStateOf ব্যবহার করা উচিত কারণ আপনি "deriving state" করছেন। তবে, এটি সম্পূর্ণরূপে ওভারহেড এবং প্রয়োজনীয় নয়, যেমনটি নিম্নলিখিত স্নিপেটে দেখানো হয়েছে:

// 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 : কম্পোজের অবস্থাকে ফ্লোতে রূপান্তর করুন

State<T> অবজেক্টগুলিকে ঠান্ডা ফ্লোতে রূপান্তর করতে snapshotFlow ব্যবহার করুন। সংগ্রহ করা হলে snapshotFlow তার ব্লকটি চালায় এবং এতে পঠিত State অবজেক্টের ফলাফল নির্গত করে। যখন snapshotFlow ব্লকের ভিতরে পঠিত State অবজেক্টগুলির মধ্যে একটি পরিবর্তিত হয়, তখন Flow তার সংগ্রাহকের কাছে নতুন মান নির্গত করবে যদি নতুন মানটি পূর্ববর্তী নির্গত মানের সমান না হয় (এই আচরণটি Flow.distinctUntilChanged এর মতো)।

নিম্নলিখিত উদাহরণে একটি পার্শ্ব প্রতিক্রিয়া দেখানো হয়েছে যা ব্যবহারকারী যখন তালিকার প্রথম আইটেমটি অতিক্রম করে বিশ্লেষণে যান তখন রেকর্ড করে:

val listState = rememberLazyListState()

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

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

উপরের কোডে, listState.firstVisibleItemIndex একটি Flow-তে রূপান্তরিত হয়েছে যা Flow-এর অপারেটরদের শক্তি থেকে উপকৃত হতে পারে।

রিস্টার্টিং এফেক্টস

Compose-এর কিছু ইফেক্ট, যেমন LaunchedEffect , produceState , অথবা DisposableEffect , বিভিন্ন সংখ্যক আর্গুমেন্ট, কী নেয়, যা চলমান প্রভাব বাতিল করতে এবং নতুন কী দিয়ে একটি নতুন শুরু করতে ব্যবহৃত হয়।

এই API গুলির জন্য সাধারণ ফর্ম হল:

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)
        }
    }
}

currentOnStart এবং currentOnStop DisposableEffect কী হিসেবে প্রয়োজন হয় না, কারণ rememberUpdatedState ব্যবহারের কারণে Composition-এ তাদের মান কখনও পরিবর্তন হয় না। যদি আপনি lifecycleOwner প্যারামিটার হিসেবে পাস না করেন এবং এটি পরিবর্তিত হয়, তাহলে HomeScreen পুনরায় কম্পোজ করে, কিন্তু DisposableEffect নিষ্পত্তি করে পুনরায় চালু করা হয় না। এর ফলে সমস্যা তৈরি হয় কারণ সেই বিন্দু থেকে ভুল lifecycleOwner ব্যবহার করা হয়।

কী হিসেবে ধ্রুবক

কল সাইটের জীবনচক্র অনুসরণ করার জন্য আপনি effect key হিসেবে true মতো একটি ধ্রুবক ব্যবহার করতে পারেন। এর জন্য বৈধ ব্যবহারের উদাহরণ রয়েছে, যেমন উপরে দেখানো LaunchedEffect উদাহরণ। তবে, এটি করার আগে, দুবার ভাবুন এবং নিশ্চিত করুন যে এটি আপনার প্রয়োজন।

{% অক্ষরে অক্ষরে %} {% এন্ডভারব্যাটিম %} {% অক্ষরে অক্ষরে %} {% এন্ডভারব্যাটিম %}