কম্পোজে রাজ্যের আয়ুষ্কাল

জেটপ্যাক কম্পোজে, কম্পোজেবল ফাংশনগুলি প্রায়শই remember ফাংশন ব্যবহার করে state ধরে রাখে। মনে রাখা মানগুলি রিকম্পোজিশন জুড়ে পুনঃব্যবহার করা যেতে পারে, যেমন State এবং Jetpack Compose এ ব্যাখ্যা করা হয়েছে।

যদিও remember রিকম্পোজিশন জুড়ে মান ধরে রাখার জন্য একটি হাতিয়ার হিসেবে কাজ করে, state কে প্রায়শই একটি রচনার জীবনকাল অতিক্রম করতে হয়। এই পৃষ্ঠাটি remember , retain , rememberSaveable , এবং rememberSerializable API গুলির মধ্যে পার্থক্য, কখন কোন API নির্বাচন করতে হবে এবং Compose-এ মনে রাখা এবং ধরে রাখা মান পরিচালনার জন্য সর্বোত্তম অনুশীলনগুলি কী তা ব্যাখ্যা করে।

সঠিক জীবনকাল বেছে নিন

কম্পোজে, কম্পোজিশন এবং তার পরেও স্টেট ধরে রাখার জন্য আপনি বেশ কয়েকটি ফাংশন ব্যবহার করতে পারেন: remember , retain , rememberSaveable , এবং rememberSerializable । এই ফাংশনগুলি তাদের জীবনকাল এবং শব্দার্থবিদ্যায় ভিন্ন, এবং প্রতিটি নির্দিষ্ট ধরণের স্টেট সংরক্ষণের জন্য উপযুক্ত। পার্থক্যগুলি নিম্নলিখিত টেবিলে বর্ণিত হয়েছে:

remember

retain

rememberSaveable , rememberSerializable

মূল্যবোধ recompositions বেঁচে?

মূল্যবোধ কি কার্যকলাপ বিনোদনে টিকে থাকে?

একই ( === ) উদাহরণটি সর্বদা ফেরত পাঠানো হবে

একটি সমতুল্য ( == ) বস্তু ফেরত পাঠানো হবে, সম্ভবত একটি ডিসিরিয়ালাইজড কপি

মূল্যবোধ কি প্রক্রিয়া মৃত্যুতেও টিকে থাকে?

সমর্থিত ডেটা প্রকার

সব

কার্যকলাপটি ধ্বংস হয়ে গেলে ফাঁস হতে পারে এমন কোনও বস্তুর উল্লেখ করা উচিত নয়।

সিরিয়ালাইজেবল হতে হবে
(হয় একটি কাস্টম Saver দিয়ে অথবা kotlinx.serialization দিয়ে)

ব্যবহারের ক্ষেত্রে

  • রচনার আওতাভুক্ত বস্তু
  • কম্পোজেবলের জন্য কনফিগারেশন অবজেক্ট
  • UI বিশ্বস্ততা না হারিয়ে পুনরায় তৈরি করা যেতে পারে এমন একটি অবস্থা
  • ক্যাশে
  • দীর্ঘস্থায়ী বা "পরিচালক" বস্তু
  • ব্যবহারকারীর ইনপুট
  • এমন অবস্থা যা অ্যাপ দ্বারা পুনরায় তৈরি করা যাবে না, যার মধ্যে রয়েছে টেক্সট ফিল্ড ইনপুট, স্ক্রোল স্টেট, টগল ইত্যাদি।

remember

Compose-এ state সংরক্ষণের সবচেয়ে সাধারণ উপায় হল remember । যখন প্রথমবার remember ডাকা হয়, তখন প্রদত্ত গণনাটি কার্যকর করা হয় এবং remember করা হয়, যার অর্থ হল এটি Compose দ্বারা ভবিষ্যতে composable দ্বারা পুনঃব্যবহারের জন্য সংরক্ষণ করা হয়। যখন একটি composable পুনরায় কম্পোজ করে, তখন এটি তার কোডটি আবার কার্যকর করে, কিন্তু remember এর যেকোনো কল আবার গণনা সম্পাদন করার পরিবর্তে পূর্ববর্তী রচনা থেকে তাদের মানগুলি ফেরত দেয়।

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

যখন একটি মনে রাখা মান আর ব্যবহার করা হয় না, তখন এটি ভুলে যায় এবং এর রেকর্ড বাতিল করা হয়। মনে রাখা মানগুলি ভুলে যায় যখন সেগুলিকে কম্পোজিশন হায়ারার্কি থেকে সরানো হয় (যখন একটি মান সরানো হয় এবং কম্পোজেবল বা MovableContent key ব্যবহার না করে অন্য কোনও স্থানে স্থানান্তর করার জন্য পুনরায় যোগ করা হয়), অথবা বিভিন্ন key প্যারামিটার সহ কল ​​করা হয়।

উপলব্ধ বিকল্পগুলির মধ্যে, remember আয়ুষ্কাল সবচেয়ে কম এবং এই পৃষ্ঠায় বর্ণিত চারটি মেমোয়াইজেশন ফাংশনের মধ্যে সবচেয়ে পুরনোটি ভুলে যায়। এটি এটিকে সবচেয়ে উপযুক্ত করে তোলে:

  • স্ক্রোল পজিশন বা অ্যানিমেশন স্টেটের মতো অভ্যন্তরীণ স্টেট অবজেক্ট তৈরি করা
  • প্রতিটি পুনর্গঠনে ব্যয়বহুল বস্তুর পুনর্নির্মাণ এড়িয়ে চলা

তবে, আপনার এড়িয়ে চলা উচিত:

  • remember দিয়ে যেকোনো ব্যবহারকারীর ইনপুট সংরক্ষণ করা, কারণ Activity কনফিগারেশন পরিবর্তন এবং সিস্টেম-ইনিশিয়েটেড প্রসেস ডেথের সময় মনে রাখা বস্তুগুলি ভুলে যায়।

rememberSaveable এবং rememberSerializable

remember এর উপরে rememberSaveable এবং rememberSerializable বিল্ড ব্যবহার করা হয়েছে। এই নির্দেশিকায় আলোচিত memoization ফাংশনগুলির মধ্যে এগুলির আয়ু সবচেয়ে বেশি। রিকম্পোজিশন জুড়ে অবজেক্টগুলিকে অবস্থানগতভাবে স্মরণ করিয়ে দেওয়ার পাশাপাশি, এটি মানগুলিও সংরক্ষণ করতে পারে যাতে সেগুলিকে কার্যকলাপ পুনর্গঠন জুড়ে পুনরুদ্ধার করা যায়, যার মধ্যে রয়েছে কনফিগারেশন পরিবর্তন এবং প্রক্রিয়া মৃত্যু (যখন সিস্টেম আপনার অ্যাপের প্রক্রিয়াটি ব্যাকগ্রাউন্ডে থাকা অবস্থায় বন্ধ করে দেয়, সাধারণত ফোরগ্রাউন্ড অ্যাপগুলির জন্য মেমোরি মুক্ত করার জন্য অথবা ব্যবহারকারী যদি আপনার অ্যাপটি চলমান থাকাকালীন অনুমতি প্রত্যাহার করে নেয়)।

rememberSerializable rememberSaveable এর মতোই কাজ করে, কিন্তু kotlinx.serialization লাইব্রেরির সাথে serializable জটিল ধরণের স্থায়ী প্রকারগুলিকে স্বয়ংক্রিয়ভাবে সমর্থন করে। যদি আপনার টাইপ @Serializable দিয়ে চিহ্নিত করা হয় (অথবা করা যেতে পারে) তাহলে rememberSerializable নির্বাচন করুন এবং অন্যান্য সকল ক্ষেত্রে rememberSaveable নির্বাচন করুন।

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

মনে রাখবেন যে rememberSaveable এবং rememberSerializable তাদের মুখস্থ করা মানগুলিকে একটি Bundle তে সিরিয়ালাইজ করে সংরক্ষণ করে। এর দুটি ফলাফল রয়েছে:

  • আপনার মুখস্থ করা মানগুলি অবশ্যই নিম্নলিখিত এক বা একাধিক ডেটা টাইপ দ্বারা প্রতিনিধিত্বযোগ্য হতে হবে: Primitives ( Int , Long , Float , Double সহ), String , অথবা এই ধরণের যেকোনো অ্যারে।
  • যখন একটি সংরক্ষিত মান পুনরুদ্ধার করা হবে, তখন এটি একটি নতুন উদাহরণ হবে যা ( == ) এর সমান, কিন্তু আগের কম্পোজিশনের মতো একই রেফারেন্স ( === ) নয়।

kotlinx.serialization ব্যবহার না করে আরও জটিল ডেটা টাইপ সংরক্ষণ করার জন্য, আপনি আপনার অবজেক্টকে সমর্থিত ডেটা টাইপে সিরিয়ালাইজ এবং ডিসিরিয়ালাইজ করার জন্য একটি কাস্টম Saver প্রয়োগ করতে পারেন। মনে রাখবেন যে Compose State , List , Map , Set ইত্যাদির মতো সাধারণ ডেটা টাইপগুলিকে বাক্সের বাইরে বোঝে এবং আপনার পক্ষে স্বয়ংক্রিয়ভাবে এগুলিকে সমর্থিত টাইপে রূপান্তর করে। Size ক্লাসের জন্য Saver এর একটি উদাহরণ নিচে দেওয়া হল। এটি listSaver ব্যবহার করে Size এর সমস্ত বৈশিষ্ট্যগুলিকে একটি তালিকায় প্যাক করে বাস্তবায়িত করা হয়।

data class Size(val x: Int, val y: Int) {
    object Saver : androidx.compose.runtime.saveable.Saver<Size, Any> by listSaver(
        save = { listOf(it.x, it.y) },
        restore = { Size(it[0], it[1]) }
    )
}

@Composable
fun rememberSize(x: Int, y: Int) {
    rememberSaveable(x, y, saver = Size.Saver) {
        Size(x, y)
    }
}

retain

retain এপিআই remember এবং rememberSaveable / rememberSerializable এর মধ্যে বিদ্যমান, এটি কতক্ষণ ধরে তার মানগুলি মনে রাখে তার পরিপ্রেক্ষিতে। এটির নামকরণ ভিন্নভাবে করা হয়েছে কারণ রিটেইন করা মানগুলি তাদের মনে রাখা প্রতিরূপগুলির চেয়ে ভিন্ন জীবনচক্রের অভিজ্ঞতা লাভ করে।

যখন একটি মান ধরে রাখা হয় , তখন এটি অবস্থানগতভাবে স্মরণীয় এবং একটি সেকেন্ডারি ডেটা স্ট্রাকচারে সংরক্ষণ করা হয় যার একটি পৃথক জীবনকাল থাকে যা অ্যাপের জীবনকালের সাথে সংযুক্ত থাকে। একটি ধরে রাখা মান সিরিয়ালাইজ না করে কনফিগারেশন পরিবর্তনগুলি টিকে থাকতে সক্ষম, কিন্তু প্রক্রিয়া মৃত্যু থেকে টিকে থাকতে পারে না। যদি কম্পোজিশন হায়ারার্কি পুনরায় তৈরি করার পরে একটি মান ব্যবহার না করা হয়, তাহলে ধরে রাখা মানটি অবসরপ্রাপ্ত হয় (যা retain ভুলে যাওয়ার সমতুল্য)।

এই ছোটো- rememberSaveable জীবনচক্রের বিনিময়ে, রিটেইন এমন মানগুলিকে ধরে রাখতে সক্ষম যা সিরিয়ালাইজ করা যায় না, যেমন ল্যাম্বডা এক্সপ্রেশন, ফ্লো এবং বিটম্যাপের মতো বৃহৎ বস্তু। উদাহরণস্বরূপ, কনফিগারেশন পরিবর্তনের সময় মিডিয়া প্লেব্যাকে বাধা রোধ করতে আপনি একটি মিডিয়া প্লেয়ার (যেমন এক্সোপ্লেয়ার) পরিচালনা করতে retain ব্যবহার করতে পারেন।

@Composable
fun MediaPlayer() {
    // Use the application context to avoid a memory leak
    val applicationContext = LocalContext.current.applicationContext
    val exoPlayer = retain { ExoPlayer.Builder(applicationContext).apply { /* ... */ }.build() }
    // ...
}

retain বনাম ViewModel

তাদের কোরে, retain এবং ViewModel উভয়ই কনফিগারেশন পরিবর্তনের সময় অবজেক্ট ইনস্ট্যান্স ধরে রাখার জন্য তাদের সর্বাধিক ব্যবহৃত ক্ষমতার ক্ষেত্রে একই রকম কার্যকারিতা প্রদান করে। retain বা ViewModel বেছে নেওয়ার পছন্দটি আপনার মান কী ধরণের ধরে রাখা হচ্ছে, এটি কীভাবে স্কোপ করা উচিত এবং আপনার অতিরিক্ত কার্যকারিতা প্রয়োজন কিনা তার উপর নির্ভর করে।

ViewModel হল এমন বস্তু যা সাধারণত আপনার অ্যাপের UI এবং ডেটা স্তরগুলির মধ্যে যোগাযোগকে অন্তর্ভুক্ত করে। এগুলি আপনাকে আপনার কম্পোজেবল ফাংশন থেকে লজিক সরানোর অনুমতি দেয়, যা টেস্টেবিলিটি উন্নত করে। ViewModel গুলি একটি ViewModelStore মধ্যে singletons হিসাবে পরিচালিত হয় এবং ধরে রাখা মান থেকে তাদের জীবনকাল আলাদা। যদিও একটি ViewModel তার ViewModelStore ধ্বংস না হওয়া পর্যন্ত সক্রিয় থাকবে, তবে যখন কন্টেন্টটি স্থায়ীভাবে কম্পোজিশন থেকে সরিয়ে দেওয়া হয় তখন ধরে রাখা মানগুলি অবসরপ্রাপ্ত হয় (উদাহরণস্বরূপ, একটি কনফিগারেশন পরিবর্তনের জন্য, এর অর্থ হল যদি UI অনুক্রম পুনরায় তৈরি করা হয় এবং ধরে রাখা মানটি ব্যবহার করা না হয় তবে একটি ধরে রাখা মান অবসরপ্রাপ্ত হয়)।

ViewModel Dagger এবং Hilt-এর সাথে নির্ভরতা ইনজেকশনের জন্য আউট-অফ-দ্য-বক্স ইন্টিগ্রেশন, SavedState সাথে ইন্টিগ্রেশন এবং ব্যাকগ্রাউন্ড টাস্ক চালু করার জন্য বিল্ট-ইন কোরোটিন সাপোর্ট অন্তর্ভুক্ত রয়েছে। এটি ViewModel ব্যাকগ্রাউন্ড টাস্ক এবং নেটওয়ার্ক অনুরোধ চালু করার জন্য, আপনার প্রকল্পের অন্যান্য ডেটা উৎসের সাথে ইন্টারঅ্যাক্ট করার জন্য এবং ঐচ্ছিকভাবে মিশন-ক্রিটিকাল UI স্টেট ক্যাপচার এবং ধরে রাখার জন্য একটি আদর্শ জায়গা করে তোলে যা ViewModel এর কনফিগারেশন পরিবর্তনের সময় ধরে রাখা উচিত এবং প্রক্রিয়ার মৃত্যু থেকে বেঁচে থাকা উচিত।

নির্দিষ্ট কম্পোজেবল ইনস্ট্যান্সের জন্য স্কোপ করা বস্তুর জন্য retain সবচেয়ে উপযুক্ত এবং ভাইবোন কম্পোজেবলের মধ্যে পুনঃব্যবহার বা ভাগ করে নেওয়ার প্রয়োজন হয় না। যেখানে ViewModel UI অবস্থা সংরক্ষণ এবং ব্যাকগ্রাউন্ড কাজ সম্পাদনের জন্য একটি ভাল জায়গা হিসেবে কাজ করে, সেখানে retain UI প্লাম্বিংয়ের জন্য বস্তু সংরক্ষণের জন্য একটি ভাল প্রার্থী যেমন ক্যাশে, ইমপ্রেশন ট্র্যাকিং এবং বিশ্লেষণ, AndroidView এর উপর নির্ভরতা এবং অন্যান্য বস্তু যা Android OS এর সাথে ইন্টারঅ্যাক্ট করে বা পেমেন্ট প্রসেসর বা বিজ্ঞাপনের মতো তৃতীয় পক্ষের লাইব্রেরি পরিচালনা করে।

আধুনিক অ্যান্ড্রয়েড অ্যাপ আর্কিটেকচারের সুপারিশের বাইরে কাস্টম অ্যাপ আর্কিটেকচার প্যাটার্ন ডিজাইন করা উন্নত ব্যবহারকারীদের জন্য: retain একটি ইন-হাউস " ViewModel -like" API তৈরি করতেও ব্যবহার করা যেতে পারে। যদিও কোরোটিন এবং সেভড-স্টেটের জন্য সমর্থন আউট-অফ-দ্য-বক্স অফার করা হয় না, retain এই ধরনের ViewModel -look-alikes এর জীবনচক্রের জন্য বিল্ডিং ব্লক হিসেবে কাজ করতে পারে যার উপরে এই বৈশিষ্ট্যগুলি তৈরি করা হয়েছে। এই ধরনের একটি উপাদান কীভাবে ডিজাইন করবেন তার সুনির্দিষ্ট বিবরণ এই নির্দেশিকার আওতার বাইরে।

retain

ViewModel

স্কোপিং

কোনও ভাগ করা মান নেই; প্রতিটি মান রচনা শ্রেণিবিন্যাসের একটি নির্দিষ্ট বিন্দুতে ধরে রাখা হয় এবং এর সাথে যুক্ত থাকে। একই ধরণের একটি ভিন্ন স্থানে ধরে রাখা সর্বদা একটি নতুন উদাহরণের উপর কাজ করে।

ViewModel হল একটি ViewModelStore মধ্যে একক সংখ্যা

ধ্বংস

রচনা শ্রেণিবিন্যাস স্থায়ীভাবে ছেড়ে যাওয়ার সময়

যখন ViewModelStore সাফ বা ধ্বংস করা হয়

অতিরিক্ত কার্যকারিতা

বস্তুটি কম্পোজিশন হায়ারার্কিতে থাকলে বা না থাকলে কলব্যাক পেতে পারে

বিল্ট-ইন coroutineScope , SavedStateHandle সমর্থন করে, Hilt ব্যবহার করে ইনজেক্ট করা যেতে পারে।

মালিকানাধীন

RetainedValuesStore

ViewModelStore

ব্যবহারের ক্ষেত্রে

  • পৃথক কম্পোজেবল দৃষ্টান্তের জন্য স্থানীয় UI-নির্দিষ্ট মানগুলি স্থায়ী হয়
  • ইমপ্রেশন ট্র্যাকিং, সম্ভবত RetainedEffect মাধ্যমে
  • একটি কাস্টম "ViewModel-like" আর্কিটেকচার কম্পোনেন্ট সংজ্ঞায়িত করার জন্য বিল্ডিং ব্লক
  • কোড সংগঠন এবং পরীক্ষার জন্য, UI এবং ডেটা স্তরগুলির মধ্যে মিথস্ক্রিয়াগুলিকে একটি পৃথক ক্লাসে এক্সট্র্যাক্ট করা
  • Flow গুলিকে State অবজেক্টে রূপান্তর করা এবং suspend ফাংশনগুলিকে কল করা যা কনফিগারেশন পরিবর্তনের দ্বারা বাধাগ্রস্ত হওয়া উচিত নয়।
  • সম্পূর্ণ স্ক্রিনের মতো বৃহৎ UI এলাকায় অবস্থা ভাগ করে নেওয়া
  • View সাথে আন্তঃকার্যক্ষমতা

retain এবং rememberSaveable অথবা rememberSerializable একত্রিত করুন

কখনও কখনও, একটি বস্তুর হাইব্রিড লাইফকাল retained এবং rememberSaveable অথবা rememberSerializable উভয়ের প্রয়োজন হয়। এটি একটি নির্দেশক হতে পারে যে আপনার বস্তুটি একটি ViewModel হওয়া উচিত, যা ViewModel গাইডের জন্য Saved State মডিউলে বর্ণিত সংরক্ষিত অবস্থা সমর্থন করতে পারে।

একই সাথে retain এবং rememberSaveable অথবা rememberSerializable ব্যবহার করা সম্ভব। উভয় জীবনচক্রকে সঠিকভাবে একত্রিত করলে তা উল্লেখযোগ্য জটিলতা তৈরি করে। আমরা আরও উন্নত এবং কাস্টম আর্কিটেকচার প্যাটার্নের অংশ হিসেবে এই প্যাটার্নটি ব্যবহার করার পরামর্শ দিচ্ছি, এবং শুধুমাত্র যখন নিম্নলিখিত সমস্ত সত্য হয়:

  • আপনি এমন একটি বস্তু সংজ্ঞায়িত করছেন যা এমন কিছু মান নিয়ে গঠিত যা ধরে রাখা বা সংরক্ষণ করা আবশ্যক (যেমন একটি বস্তু যা ব্যবহারকারীর ইনপুট এবং একটি ইন-মেমরি ক্যাশে ট্র্যাক করে যা ডিস্কে লেখা যায় না)।
  • আপনার অবস্থাটি একটি কম্পোজেবলের মধ্যে সীমাবদ্ধ এবং ViewModel এর সিঙ্গেলটন স্কোপিং বা জীবনকালের জন্য উপযুক্ত নয়।

যখন এই সবগুলোই ঠিক থাকে, তখন আমরা আপনার ক্লাসকে তিন ভাগে ভাগ করার পরামর্শ দিচ্ছি: সংরক্ষিত ডেটা, সংরক্ষিত ডেটা এবং একটি "মধ্যস্থতাকারী" অবজেক্ট যার নিজস্ব কোনও অবস্থা নেই এবং সেই অনুযায়ী আপডেট অবস্থা দেওয়ার জন্য সংরক্ষিত এবং সংরক্ষিত অবজেক্টগুলিতে প্রতিনিধিত্ব করে। এই প্যাটার্নটি নিম্নলিখিত আকার ধারণ করে:

@Composable
fun rememberAndRetain(): CombinedRememberRetained {
    val saveData = rememberSerializable(serializer = serializer<ExtractedSaveData>()) {
        ExtractedSaveData()
    }
    val retainData = retain { ExtractedRetainData() }
    return remember(saveData, retainData) {
        CombinedRememberRetained(saveData, retainData)
    }
}

@Serializable
data class ExtractedSaveData(
    // All values that should persist process death should be managed by this class.
    var savedData: AnotherSerializableType = defaultValue()
)

class ExtractedRetainData {
    // All values that should be retained should appear in this class.
    // It's possible to manage a CoroutineScope using RetainObserver.
    // See the full sample for details.
    var retainedData = Any()
}

class CombinedRememberRetained(
    private val saveData: ExtractedSaveData,
    private val retainData: ExtractedRetainData,
) {
    fun doAction() {
        // Manipulate the retained and saved state as needed.
    }
}

জীবনকাল অনুসারে অবস্থা পৃথক করার মাধ্যমে, দায়িত্ব এবং সংরক্ষণের বিভাজন খুব স্পষ্ট হয়ে ওঠে। এটি ইচ্ছাকৃতভাবে করা হয়েছে যে সংরক্ষণ ডেটা রিটেন ডেটা দ্বারা ম্যানিপুলেট করা যাবে না, কারণ এটি এমন একটি পরিস্থিতি প্রতিরোধ করে যেখানে savedInstanceState বান্ডেলটি ইতিমধ্যেই ক্যাপচার করা হয়ে গেলে এবং আপডেট করা না গেলে একটি সংরক্ষণ ডেটা আপডেটের চেষ্টা করা হয়। এটি Compose-এ কল না করে বা কোনও Activity রিক্রিয়েশন সিমুলেট না করে আপনার কনস্ট্রাক্টর পরীক্ষা করে বিনোদন পরিস্থিতি পরীক্ষা করার অনুমতি দেয়।

এই প্যাটার্নটি কীভাবে বাস্তবায়িত হতে পারে তার একটি সম্পূর্ণ উদাহরণের জন্য সম্পূর্ণ নমুনা ( RetainAndSaveSample.kt ) দেখুন।

অবস্থানগত স্মৃতিচিহ্ন এবং অভিযোজিত বিন্যাস

অ্যান্ড্রয়েড অ্যাপ্লিকেশনগুলি ফোন, ফোল্ডেবল, ট্যাবলেট এবং ডেস্কটপ সহ অনেক ফর্ম ফ্যাক্টর সমর্থন করতে পারে। অ্যাপ্লিকেশনগুলিকে প্রায়শই অ্যাডাপ্টিভ লেআউট ব্যবহার করে এই ফর্ম ফ্যাক্টরগুলির মধ্যে স্থানান্তর করতে হয়। উদাহরণস্বরূপ, ট্যাবলেটে চলমান একটি অ্যাপ দুই-কলামের তালিকা-বিস্তারিত দৃশ্য দেখাতে সক্ষম হতে পারে, তবে ছোট ফোন স্ক্রিনে উপস্থাপিত হলে একটি তালিকা এবং বিশদ পৃষ্ঠার মধ্যে নেভিগেট করতে পারে।

যেহেতু মনে রাখা এবং ধরে রাখা মানগুলি অবস্থানগতভাবে মুখস্থ করা হয়, তাই রচনা অনুক্রমের একই বিন্দুতে উপস্থিত হলেই কেবল সেগুলি পুনরায় ব্যবহার করা হয়। আপনার লেআউটগুলি বিভিন্ন ফর্ম ফ্যাক্টরের সাথে খাপ খাইয়ে নেওয়ার সাথে সাথে, তারা আপনার রচনা অনুক্রমের কাঠামো পরিবর্তন করতে পারে এবং ভুলে যাওয়া মানগুলির দিকে পরিচালিত করতে পারে।

ListDetailPaneScaffold এবং NavDisplay (Jetpack Navigation 3 থেকে) এর মতো আউট-অফ-দ্য-বক্স কম্পোনেন্টের জন্য, এটি কোনও সমস্যা নয় এবং লেআউট পরিবর্তনের সময়ও আপনার অবস্থা বজায় থাকবে। ফর্ম ফ্যাক্টরের সাথে খাপ খাইয়ে নেওয়া কাস্টম কম্পোনেন্টের জন্য, নিম্নলিখিতগুলির মধ্যে একটি করে নিশ্চিত করুন যে লেআউট পরিবর্তনের দ্বারা অবস্থা প্রভাবিত না হয়:

  • নিশ্চিত করুন যে স্টেটফুল কম্পোজেবলগুলি সর্বদা রচনা শ্রেণিবিন্যাসে একই স্থানে ডাকা হয়। রচনা শ্রেণিবিন্যাসে বস্তুগুলিকে স্থানান্তর করার পরিবর্তে লেআউট লজিক পরিবর্তন করে অভিযোজিত লেআউটগুলি বাস্তবায়ন করুন।
  • স্টেটফুল কম্পোজেবলগুলিকে সুন্দরভাবে স্থানান্তর করতে MovableContent ব্যবহার করুন। MovableContent এর উদাহরণগুলি মনে রাখা এবং ধরে রাখা মানগুলিকে তাদের পুরানো অবস্থান থেকে নতুন অবস্থানে স্থানান্তর করতে সক্ষম।

কারখানার কার্যকারিতা মনে রাখবেন

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

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

  • ফাংশনের নামের পূর্বে remember লিখুন। ঐচ্ছিকভাবে, যদি ফাংশন বাস্তবায়নটি retained বস্তুর উপর নির্ভর করে এবং API কখনই remember এর ভিন্ন রূপের উপর নির্ভর করতে বিকশিত না হয়, তাহলে retain প্রিফিক্স ব্যবহার করুন।
  • যদি state persistence বেছে নেওয়া হয় এবং সঠিক Saver বাস্তবায়ন লেখা সম্ভব হয়, তাহলে rememberSaveable অথবা rememberSerializable ব্যবহার করুন।
  • CompositionLocal এর উপর ভিত্তি করে পার্শ্ব প্রতিক্রিয়া বা ইনিশিয়ালাইজিং মানগুলি এড়িয়ে চলুন যা ব্যবহারের সাথে প্রাসঙ্গিক নাও হতে পারে। মনে রাখবেন, আপনার অবস্থা যেখানে তৈরি করা হয়েছে সেখানে এটি ব্যবহার করা নাও হতে পারে।

@Composable
fun rememberImageState(
    imageUri: String,
    initialZoom: Float = 1f,
    initialPanX: Int = 0,
    initialPanY: Int = 0
): ImageState {
    return rememberSaveable(imageUri, saver = ImageState.Saver) {
        ImageState(
            imageUri, initialZoom, initialPanX, initialPanY
        )
    }
}

data class ImageState(
    val imageUri: String,
    val zoom: Float,
    val panX: Int,
    val panY: Int
) {
    object Saver : androidx.compose.runtime.saveable.Saver<ImageState, Any> by listSaver(
        save = { listOf(it.imageUri, it.zoom, it.panX, it.panY) },
        restore = { ImageState(it[0] as String, it[1] as Float, it[2] as Int, it[3] as Int) }
    )
}