Jetpack Compose-এ, কম্পোজেবল ফাংশন প্রায়ই remember
ফাংশন ব্যবহার করে স্টেট হোল্ড করে। স্টেট ও Jetpack Compose-এ ব্যাখ্যা করা হয়েছে,
সেই অনুযায়ী, মনে রাখা ভ্যালুগুলি আবার কম্পোজ করার সময় আবার ব্যবহার করা যেতে পারে।
remember, রিকম্পোজিশন জুড়ে ভ্যালু বজায় রাখার টুল হিসেবে কাজ করলেও, স্টেটকে
প্রায়শই কম্পোজিশনের লাইফটাইমের বাইরেও থাকতে হয়। এই পৃষ্ঠায় remember, retain, rememberSaveable,
এবং rememberSerializable API-এর মধ্যে পার্থক্য, কোন API কখন বেছে নিতে হবে এবং Compose-এ মনে রাখা ও ধরে রাখা ভ্যালু ম্যানেজ করার
জন্য সেরা পদ্ধতি কী কী, সেই সম্পর্কে ব্যাখ্যা করা হয়েছে।
সঠিক মেয়াদ বেছে নিন
কম্পোজ করার সময়, কম্পোজিশন ও তার বাইরে স্টেট পারসিস্ট করার জন্য আপনি
একাধিক ফাংশন ব্যবহার করতে পারেন: remember, retain, rememberSaveable এবং
rememberSerializable। এইসব ফাংশনের মেয়াদ ও অর্থগত দিক থেকে পার্থক্য রয়েছে,
এবং প্রতিটি ফাংশন নির্দিষ্ট ধরনের স্টেট সেভ করার জন্য উপযুক্ত। নিম্নলিখিত টেবিলে পার্থক্যগুলি
দেখানো হয়েছে:
|
|
|
|
|---|---|---|---|
ভ্যালু কি রিকম্পোজিশনের পরেও থাকে? |
✅ |
✅ |
✅ |
অ্যাক্টিভিটি আবার তৈরি করার পরেও কি ভ্যালু থেকে যায়? |
❌ |
✅ একই ( |
✅ সমতুল্য ( |
প্রসেস বন্ধ হয়ে গেলেও কি ভ্যালু থেকে যায়? |
❌ |
❌ |
✅ |
যেসব ডেটার ধরন কাজ করে |
সব |
অ্যাক্টিভিটি ধ্বংস হয়ে গেলে লিক হয়ে যাবে এমন কোনও অবজেক্টের রেফারেন্স দেওয়া যাবে না |
অবশ্যই সিরিয়ালাইজ করা যায় এমন হতে হবে |
উদাহরণ |
|
|
|
remember
Compose-এ স্টেট স্টোর করার সবচেয়ে সাধারণ উপায় হল remember। remember প্রথমবার কল করা হলে, প্রদত্ত গণনা এক্সিকিউট করা হয় এবং তা
মনে রাখা হয়, অর্থাৎ কম্পোজ করার মতো আইটেম দ্বারা ভবিষ্যতে আবার ব্যবহার করার জন্য
Compose-এ এটি স্টোর করা হয়। কোনও কম্পোজ করার উপযুক্ত আইটেম আবার কম্পোজ করা হলে, এটি আবার নিজের কোড এক্সিকিউট করে, কিন্তু কোনও
remember-এ কল করলে, সেটি আবার গণনা এক্সিকিউট করার পরিবর্তে
আগের কম্পোজিশন থেকে তার ভ্যালু রিটার্ন করে।
কম্পোজ করা যায় এমন ফাংশনের প্রতিটি ইনস্ট্যান্সের নিজস্ব মনে রাখা ভ্যালুর সেট থাকে, যেগুলিকে পজিশনাল মেমোরাইজেশন বলা হয়। রিম্যাপিং জুড়ে ব্যবহারের জন্য মনে রাখা ভ্যালু মেমরাইজ করা হলে, সেগুলি কম্পোজিশন হায়ারার্কিতে তাদের পজিশনের সাথে যুক্ত থাকে। কোনও কম্পোজ করার মতো আইটেম বিভিন্ন লোকেশনে ব্যবহার করা হলে, কম্পোজিশন হায়ারার্কিতে প্রতিটি ইনস্ট্যান্সের নিজস্ব মনে রাখা ভ্যালুর সেট থাকে।
মনে রাখা কোনও ভ্যালু আর ব্যবহার করা না হলে, সেটি ভুলে যাওয়া হয় এবং তার রেকর্ড
বাদ দেওয়া হয়। কম্পোজিশন হায়ারার্কি থেকে সরিয়ে দিলে মনে রাখা ভ্যালু ভুলে যাওয়া হয় (এর মধ্যে অন্তর্ভুক্ত হল, key কম্পোজ করা যায় বা
MovableContent ব্যবহার না করে কোনও ভ্যালু সরিয়ে দিয়ে
অন্য লোকেশনে যোগ করা), অথবা আলাদা key প্যারামিটার দিয়ে কল করা।
উপলভ্য বিকল্পগুলির মধ্যে, remember-এর লাইফস্প্যান সবচেয়ে কম এবং এই পৃষ্ঠায় বর্ণিত চারটি মেমোরাইজেশন ফাংশনের মধ্যে
এটি সবচেয়ে আগে ভ্যালু ভুলে যায়।
এটি এইসব কাজের জন্য সবচেয়ে উপযুক্ত:
- স্ক্রল পজিশন বা অ্যানিমেশন স্টেটের মতো ইন্টার্নাল স্টেট অবজেক্ট তৈরি করা
- প্রতিবার রিকম্পোজিশনের সময় দামি অবজেক্ট নতুন করে তৈরি করা এড়ানো
তবে, এগুলি এড়িয়ে চলুন:
remember-এর সাথে ব্যবহারকারীর ইনপুট সেভ করা, কারণ অ্যাক্টিভিটি কনফিগারেশন পরিবর্তন এবং সিস্টেম-ইনিশিয়েটেড প্রসেস ডেথ জুড়ে মনে রাখা অবজেক্ট ভুলে যাওয়া হয়।
rememberSaveable ও rememberSerializable
rememberSaveable ও rememberSerializable, remember-এর উপরে তৈরি করা হয়েছে। এই গাইডটিতে আলোচনা করা মেমরাইজেশন ফাংশনগুলির মধ্যে এগুলির
লাইফস্প্যান সবচেয়ে বেশি।
রীকম্পোজিশন জুড়ে পজিশনাল মেমোইজ অবজেক্ট ছাড়াও, এটি ভ্যালু
সেভ করতে পারে যাতে অ্যাক্টিভিটি রিক্রিয়েশন জুড়ে সেগুলি রিস্টোর করা যায়,
এর মধ্যে কনফিগারেশন পরিবর্তন এবং প্রসেস ডেথ (সিস্টেম ব্যাকগ্রাউন্ডে থাকাকালীন আপনার অ্যাপের
প্রসেস বন্ধ করে দেয়, সাধারণত এটি করা হয় যাতে ফোরগ্রাউন্ড অ্যাপের জন্য মেমরি খালি করা যায়
অথবা আপনার অ্যাপ চলাকালীন ব্যবহারকারী অনুমতি প্রত্যাহার করে নিলে) অন্তর্ভুক্ত।
rememberSerializable rememberSaveable-এর মতোই কাজ করে, তবে
kotlinx.serialization লাইব্রেরির সাথে সিরিয়ালাইজ করা যায় এমন জটিল ধরনের ডেটা অটোমেটিক
সেভ করে রাখে। আপনার ধরন @Serializable দিয়ে চিহ্নিত করা হলে rememberSerializable বেছে নিন
এবং অন্য সব ক্ষেত্রে rememberSaveable বেছে নিন।
এর ফলে rememberSaveable ও rememberSerializable দু'টিই ব্যবহারকারীর ইনপুট সম্পর্কিত স্টেট সেভ করার জন্য উপযুক্ত
হয়ে ওঠে, এর মধ্যে টেক্সট ফিল্ড এন্ট্রি, স্ক্রল
পজিশন, টগল স্টেট ইত্যাদি পড়ে। ব্যবহারকারী যাতে
কখনও তার জায়গা না হারান তা নিশ্চিত করতে আপনাকে এই স্টেট সেভ করতে হবে। সাধারণত, আপনার অ্যাপ কোনও ডাটাবেসের মতো অন্য কোনও পারসিস্টেন্ট ডেটা সোর্স থেকে
যেসব স্টেট রিট্রিভ করতে পারছে না, সেগুলি মেমোরাইজ করার জন্য আপনাকে rememberSaveable বা
rememberSerializable ব্যবহার করতে হবে।
মনে রাখবেন যে rememberSaveable এবং rememberSerializable তাদের মেমোরাইজ করা
ভ্যালু Bundle-এ সিরিয়ালাইজ করে সেভ করে। এর ফলে দুটি বিষয় ঘটে:
- মেমরাইজ করা ভ্যালুগুলিকে নিম্নলিখিত ডেটা
টাইপের এক বা একাধিক আইটেম দিয়ে রিপ্রেজেন্ট করতে হবে: প্রিমিটিভ (
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 API, remember এবং
rememberSaveable/rememberSerializable-এর মধ্যে থাকে, এর ভ্যালু কতক্ষণ
মেমোরাইজ করে সেই হিসেবে। এর নাম আলাদা কারণ রিটেন করা ভ্যালুগুলিও তাদের মনে রাখা সমকক্ষদের থেকে আলাদা লাইফসাইকেল
অনুভব করে।
কোনও ভ্যালু রিটেন করা হলে, সেটি পজিশনাল মেমোরাইজ করা হয় এবং একটি
সেকেন্ডারি ডেটা স্ট্রাকচারে সেভ করা হয়, যার আলাদা লাইফস্প্যান থাকে যা অ্যাপের
লাইফস্প্যানের সাথে যুক্ত থাকে। রিটেন করা ভ্যালু সিরিয়ালাইজ না করেই কনফিগারেশন পরিবর্তন
হয়ে গেলেও টিকে থাকতে পারে, কিন্তু প্রসেস বন্ধ হয়ে গেলে টিকে থাকতে পারে না। কম্পোজিশন হায়ারার্কি আবার তৈরি করার পরে কোনও ভ্যালু ব্যবহার করা না হলে, রিটেন করা ভ্যালু রিটায়ার হয়ে যায় (যা
retain-এর ক্ষেত্রে ভুলে যাওয়ার সমতুল্য)।
এই rememberSaveableলাইফসাইকেল -এর তুলনায় ছোট হওয়ার বিনিময়ে, retain এমন ভ্যালু
পারসিস্ট করতে পারে যা সিরিয়ালাইজ করা যায় না, যেমন ল্যাম্বডা এক্সপ্রেশন, ফ্লো এবং
বিটম্যাপের মতো বড় অবজেক্ট। যেমন, কনফিগারেশনে পরিবর্তন করার সময় মিডিয়া প্লেব্যাকের
বাধা এড়াতে, আপনি মিডিয়া
প্লেয়ার (যেমন, ExoPlayer) ম্যানেজ করতে 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-এর মধ্যে কোনটি বেছে নেবেন তা নির্ভর করে
আপনি কোন ধরনের ভ্যালু পারসিস্ট করছেন, সেটি কীভাবে স্কোপ করা উচিত এবং আপনার
অতিরিক্ত ফাংশনালিটির প্রয়োজন আছে কিনা, এই বিষয়গুলির উপর।
ViewModels হল এমন অবজেক্ট যা সাধারণত আপনার অ্যাপের UI এবং ডেটা লেয়ারের মধ্যে
যোগাযোগকে এনক্যাপসুলেট করে। এগুলি আপনাকে কম্পোজ করা যায় এমন ফাংশন থেকে
লজিক সরিয়ে নিতে দেয়, যা টেস্ট করার উপযুক্ততা উন্নত করে। ViewModel-কে ViewModelStore-এর মধ্যে
সিঙ্গেলটন হিসেবে ম্যানেজ করা হয় এবং রিটেন করা
ভ্যালুর থেকে এগুলির মেয়াদ আলাদা হয়। ViewModel যতক্ষণ ViewModelStore ধ্বংস না হয় ততক্ষণ অ্যাক্টিভ থাকে, তবে কন্টেন্ট কম্পোজিশন থেকে স্থায়ীভাবে সরিয়ে দেওয়া হলে
রিটেন ভ্যালু বাতিল হয়ে যায় (যেমন, কনফিগারেশন পরিবর্তনের ক্ষেত্রে, এর অর্থ হল যে
UI হায়ারার্কি আবার তৈরি করা হলে এবং কম্পোজিশন আবার তৈরি করার পরে রিটেন
ভ্যালু ব্যবহার না করা হলে, রিটেন ভ্যালু বাতিল হয়ে যায়)।
ViewModel-এ Dagger ও Hilt-এর সাথে ডিপেন্ডেন্সি ইনজেকশনের
আউট-অফ-দ্য-বক্স ইন্টিগ্রেশন, SavedState-এর সাথে ইন্টিগ্রেশন এবং ব্যাকগ্রাউন্ড টাস্ক লঞ্চ করার জন্য বিল্ট-ইন কোরাউটিন
সাপোর্টও অন্তর্ভুক্ত। এর ফলে ViewModel হল
ব্যাকগ্রাউন্ড টাস্ক ও নেটওয়ার্ক অনুরোধ লঞ্চ করার, আপনার প্রজেক্টে
অন্যান্য ডেটা সোর্সের সাথে ইন্টার্যাক্ট করার এবং ঐচ্ছিকভাবে এমন মিশন-ক্রিটিক্যাল UI স্টেট ক্যাপচার ও পারসিস্ট করার
জন্য আদর্শ জায়গা যা ViewModel-এ কনফিগারেশন পরিবর্তন জুড়ে ধরে রাখতে হবে এবং
প্রসেস ডেথ থেকে বেঁচে থাকতে হবে।
retain নির্দিষ্ট কম্পোজ করার উপযুক্ত
ইনস্ট্যান্সের জন্য স্কোপ করা অবজেক্টের জন্য সবচেয়ে উপযুক্ত এবং এর জন্য একই ধরনের কম্পোজ করার উপযুক্ত আইটেমের মধ্যে আবার ব্যবহার বা শেয়ার করার প্রয়োজন হয় না। কোথায়
ViewModel UI স্টেট স্টোর করা ও ব্যাকগ্রাউন্ড টাস্ক পারফর্ম করার জন্য ভালো জায়গা হিসেবে কাজ করে,
retain হল ক্যাশে, ইম্প্রেশন ট্র্যাকিং ও অ্যানালিটিক্স, AndroidView-এর উপর নির্ভরতা এবং অন্যান্য
অবজেক্টের মতো UI প্লাম্বিংয়ের জন্য অবজেক্ট স্টোর করার জন্য ভালো ক্যান্ডিডেট, যা Android OS-এর সাথে ইন্টার্যাক্ট করে অথবা
পেমেন্ট প্রসেসর বা বিজ্ঞাপনের মতো থার্ড-পার্টি লাইব্রেরি ম্যানেজ করে।
উন্নত ব্যবহারকারীদের জন্য, যারা
আধুনিক Android অ্যাপ আর্কিটেকচার সংক্রান্ত সাজেশনের বাইরে কাস্টম অ্যাপ আর্কিটেকচার প্যাটার্ন ডিজাইন করছেন: retain এটি "ViewModel-এর মতো" ইন্টার্নাল API
তৈরি করতেও ব্যবহার করা যেতে পারে। যদিও কোরাউটিন ও
সেভ করা-স্টেটের জন্য বক্সের বাইরে সহায়তা প্রদান করা হয় না, তবে retain এই ধরনের ViewModel-এর মতো দেখতে আইটেমের লাইফসাইকেলের জন্য বিল্ডিং
ব্লক হিসেবে কাজ করতে পারে, যার উপরে এইসব ফিচার
বিল্ট-ইন করা আছে। এই ধরনের কম্পোনেন্ট কীভাবে ডিজাইন করতে হয় সেই বিষয়ে বিস্তারিত তথ্য এই নির্দেশিকার
পরিধির বাইরে।
|
|
|
|---|---|---|
স্কোপিং |
কোনও শেয়ার করা ভ্যালু নেই; প্রতিটি ভ্যালু কম্পোজিশন হায়ারার্কির নির্দিষ্ট পয়েন্টে ধরে রাখা হয় এবং তার সাথে যুক্ত থাকে। একই ধরনের ডেটা আলাদা লোকেশনে রাখলে সবসময় নতুন ইনস্ট্যান্স তৈরি হয়। |
|
ধ্বংস |
কম্পোজিশন হায়ারার্কি থেকে স্থায়ীভাবে বেরিয়ে আসার সময় |
|
অতিরিক্ত কার্যকারিতা |
অবজেক্টটি কম্পোজিশন হায়ারার্কিতে থাকলে বা না থাকলে কলব্যাক পেতে পারে |
বিল্ট-ইন |
মালিক |
|
|
ব্যবহারের ক্ষেত্র |
|
|
retain ও rememberSaveable অথবা rememberSerializable-কে একত্রিত করুন
কখনও কখনও, কোনও অবজেক্টের retained এবং
rememberSaveable বা rememberSerializable, দু'টিই হাইব্রিড লাইফস্প্যান থাকতে হবে। এটি এমন একটি ইঙ্গিত হতে পারে যে আপনার
অবজেক্টটি একটি ViewModel হওয়া উচিত, যা ViewModel গাইডের জন্য সেভ করা স্টেট মডিউলে
বর্ণিত সেভ করা স্টেটকে সাপোর্ট করতে পারে।
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-এ কল না করে বা কোনও অ্যাক্টিভিটি
রিক্রিয়েশন সিমুলেট না করে আপনার কনস্ট্রাক্টর পরীক্ষা করে
রিক্রিয়েশন পরিস্থিতি পরীক্ষা করার অনুমতি দেয়।
এই প্যাটার্ন কীভাবে প্রয়োগ করা যেতে পারে তার সম্পূর্ণ উদাহরণ পেতে
সম্পূর্ণ স্যাম্পেল (RetainAndSaveSample.kt) দেখুন।
পজিশনাল মেমোরাইজেশন ও অ্যাডাপ্টিভ লেআউট
Android অ্যাপ্লিকেশন ফোন, ফোল্ড করা যায় এমন ডিভাইস, ট্যাবলেট ও ডেস্কটপ সহ বিভিন্ন ফর্ম ফ্যাক্টরে কাজ করতে পারে। অ্যাপ্লিকেশনগুলিকে প্রায়ই অ্যাডাপ্টিভ লেআউট ব্যবহার করে এইসব ফর্ম ফ্যাক্টরের মধ্যে ট্রানজিশন করতে হয়। যেমন, ট্যাবলেটে চলা কোনও অ্যাপ দুটি কলামের তালিকা-বিবরণ ভিউ দেখাতে পারলেও, ছোট ফোনের স্ক্রিনে দেখানো হলে তালিকা ও বিবরণ পৃষ্ঠার মধ্যে নেভিগেট করতে পারে।
মনে রাখা ও ধরে রাখা ভ্যালুগুলি পজিশন অনুযায়ী মেমোরাইজ করা হয়, তাই সেগুলি কম্পোজিশন হায়ারার্কির একই পয়েন্টে দেখা গেলে তবেই আবার ব্যবহার করা যায়। আপনার লেআউট বিভিন্ন ফর্ম ফ্যাক্টরের সাথে মানিয়ে নেওয়ার সময়, সেগুলি আপনার কম্পোজিশন হায়ারার্কির স্ট্রাকচার পরিবর্তন করতে পারে এবং এর ফলে ভ্যালু ভুলে যাওয়া হতে পারে।
ListDetailPaneScaffold এবং NavDisplay
(Jetpack Navigation 3 থেকে) এর মতো আউট-অফ-দ্য-বক্স কম্পোনেন্টের জন্য, এটি কোনও সমস্যা নয় এবং লেআউট পরিবর্তন জুড়ে
আপনার স্টেট বজায় থাকবে। ফর্ম ফ্যাক্টর অনুযায়ী কাস্টম কম্পোনেন্টের ক্ষেত্রে,
নিচের যেকোনও একটি কাজ করে লেআউট পরিবর্তনের ফলে স্টেট প্রভাবিত হচ্ছে না কিনা তা নিশ্চিত করুন:
- কম্পোজিশন হায়ারার্কিতে স্টেটফুল কম্পোজ করার মতো আইটেম যেন সবসময় একই জায়গায় কল করা হয় তা নিশ্চিত করুন। কম্পোজিশন হায়ারার্কিতে অবজেক্টের লোকেশন পরিবর্তন করার পরিবর্তে লেআউট লজিক পরিবর্তন করে অ্যাডাপ্টিভ লেআউট প্রয়োগ করুন।
- স্টেটফুল কম্পোজ করার উপযুক্ত আইটেমকে সাবলীলভাবে অন্য জায়গায় সরাতে
MovableContentব্যবহার করুন।MovableContent-এর ইনস্ট্যান্স তাদের পুরনো লোকেশন থেকে মনে রাখা ও রিটেন করা ভ্যালু নতুন লোকেশনে সরাতে পারে।
ফ্যাক্টরি ফাংশন মনে রাখা
যদিও কম্পোজ UI কম্পোজ করার উপযুক্ত ফাংশন দিয়ে তৈরি হয়, তবে অনেক অবজেক্ট
কম্পোজিশন তৈরি ও সাজানোর কাজে লাগে। এর সবচেয়ে সাধারণ উদাহরণ হল
কমপ্লেক্স কম্পোজ করার উপযুক্ত অবজেক্ট যা নিজের স্টেটকে সংজ্ঞায়িত করে, যেমন LazyList,
যা LazyListState গ্রহণ করে।
Compose-কেন্দ্রিক অবজেক্টকে সংজ্ঞায়িত করার সময়, আমরা remember
ফাংশন তৈরি করার পরামর্শ দিই। এর মাধ্যমে, উদ্দেশ্য অনুযায়ী মনে রাখার আচরণকে সংজ্ঞায়িত করা যায়। এর মধ্যে লাইফস্প্যান
এবং মূল ইনপুট অন্তর্ভুক্ত। এর ফলে আপনার রাজ্যের গ্রাহকরা কম্পোজিশন হায়ারার্কিতে আত্মবিশ্বাসের সাথে
ইনস্ট্যান্স তৈরি করতে পারবেন যা টিকে থাকবে এবং প্রত্যাশিতভাবে
ইনভ্যালিড হয়ে যাবে। কম্পোজ করা যায় এমন ফ্যাক্টরি ফাংশন নির্ধারণ করার সময়, এইসব নির্দেশিকা মেনে চলুন:
- ফাংশনের নামের আগে
rememberযোগ করুন। বিকল্প হিসেবে, যদি ফাংশন ইমপ্লিমেন্টেশনretainedঅবজেক্টের উপর নির্ভর করে এবং API কখনওইremember-এর অন্য কোনও ভেরিয়েন্টের উপর নির্ভর করার জন্য বিবর্তিত হবে না, তাহলেretainপ্রিফিক্স ব্যবহার করুন। - স্টেট পারসিস্টেন্স বেছে নেওয়া হলে এবং সঠিক
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) } ) }