যখন কোনো অস্থিতিশীল ক্লাসের সম্মুখীন হন যা পারফরম্যান্সের সমস্যা সৃষ্টি করে, তখন সেটিকে স্থিতিশীল করা উচিত। এই ডকুমেন্টটিতে এমন কয়েকটি কৌশলের রূপরেখা দেওয়া হয়েছে যা আপনি এই কাজটি করার জন্য ব্যবহার করতে পারেন।
শক্তিশালী স্কিপিং সক্ষম করুন
আপনার প্রথমে স্ট্রং স্কিপিং মোড চালু করার চেষ্টা করা উচিত। স্ট্রং স্কিপিং মোডের মাধ্যমে অস্থিতিশীল প্যারামিটারযুক্ত কম্পোজেবল ফাইলগুলোকে এড়িয়ে যাওয়া যায় এবং স্থিতিশীলতাজনিত পারফরম্যান্স সমস্যা সমাধানের এটিই সবচেয়ে সহজ উপায়।
আরও তথ্যের জন্য স্ট্রং স্কিপিং দেখুন।
ক্লাসটিকে অপরিবর্তনীয় করুন
আপনি একটি অস্থিতিশীল ক্লাসকে সম্পূর্ণ অপরিবর্তনীয় করার চেষ্টাও করতে পারেন।
- অপরিবর্তনশীল (Immutable ): এমন একটি টাইপকে বোঝায় যেখানে একবার কোনো ইনস্ট্যান্স তৈরি হয়ে গেলে তার কোনো প্রোপার্টির মান আর কখনো পরিবর্তন করা যায় না এবং এর সমস্ত মেথড রেফারেন্সগতভাবে স্বচ্ছ (referenceally transparent) হয়।
- নিশ্চিত করুন যে ক্লাসের সমস্ত প্রোপার্টি
varএর পরিবর্তেvalএবং অপরিবর্তনীয় টাইপের। -
String, Int, এবংFloatমতো প্রিমিটিভ টাইপগুলো সর্বদা অপরিবর্তনশীল। - যদি এটি অসম্ভব হয়, তাহলে যেকোনো পরিবর্তনযোগ্য প্রপার্টির জন্য আপনাকে অবশ্যই কম্পোজ স্টেট ব্যবহার করতে হবে।
- নিশ্চিত করুন যে ক্লাসের সমস্ত প্রোপার্টি
- Stable : এমন একটি টাইপ নির্দেশ করে যা পরিবর্তনযোগ্য। টাইপটির কোনো পাবলিক প্রোপার্টি বা মেথডের আচরণ পূর্ববর্তী কোনো আহ্বানের চেয়ে ভিন্ন ফলাফল দেবে কি না, সে বিষয়ে Compose রানটাইম অবগত হয় না।
অপরিবর্তনীয় সংগ্রহ
Compose যে কারণে একটি ক্লাসকে অস্থিতিশীল (unstable) বলে মনে করে, তার একটি সাধারণ কারণ হলো কালেকশন (collections)। 'স্থিতিশীলতার সমস্যা নির্ণয়' (Diagnose stability issues) পৃষ্ঠায় যেমন উল্লেখ করা হয়েছে, Compose কম্পাইলার List, Map , এবং Set মতো কালেকশনগুলো সত্যিই অপরিবর্তনীয় (immutable) কিনা সে বিষয়ে সম্পূর্ণ নিশ্চিত হতে পারে না এবং তাই সেগুলোকে অস্থিতিশীল হিসেবে চিহ্নিত করে।
এর সমাধান করতে, আপনি ইমিউটেবল কালেকশন ব্যবহার করতে পারেন। কম্পোজ কম্পাইলারে কোটলিনক্স ইমিউটেবল কালেকশনের জন্য সাপোর্ট রয়েছে। এই কালেকশনগুলো ইমিউটেবল হওয়ার জন্যই ডিজাইন করা হয়েছে, এবং কম্পোজ কম্পাইলারও সেভাবেই এগুলোকে বিবেচনা করে। এই লাইব্রেরিটি এখনও আলফা পর্যায়ে রয়েছে, তাই এর এপিআই-তে সম্ভাব্য পরিবর্তন আশা করা যায়।
স্থিতিশীলতার সমস্যা নির্ণয় নির্দেশিকা থেকে এই অস্থিতিশীল শ্রেণীটি পুনরায় বিবেচনা করুন:
unstable class Snack {
…
unstable val tags: Set<String>
…
}
একটি অপরিবর্তনশীল কালেকশন ব্যবহার করে আপনি tags স্থিতিশীল করতে পারেন। ক্লাসের মধ্যে, tags টাইপ পরিবর্তন করে ImmutableSet<String> করুন:
data class Snack{
…
val tags: ImmutableSet<String> = persistentSetOf()
…
}
এটি করার পর, ক্লাসের সমস্ত প্যারামিটার অপরিবর্তনীয় হয়ে যায় এবং কম্পোজ কম্পাইলার ক্লাসটিকে স্থিতিশীল হিসেবে চিহ্নিত করে।
Stable বা Immutable দিয়ে টীকা দিন
স্থিতিশীলতার সমস্যা সমাধানের একটি সম্ভাব্য উপায় হলো অস্থিতিশীল ক্লাসগুলোকে @Stable অথবা @Immutable দিয়ে টীকাযুক্ত করা।
একটি ক্লাসকে অ্যানোটেট করার অর্থ হলো, কম্পাইলার আপনার ক্লাস সম্পর্কে স্বাভাবিকভাবে যা অনুমান করত, তাকে অগ্রাহ্য করা। এটি কোটলিনের !! অপারেটরের মতো। এই অ্যানোটেশনগুলো ব্যবহারের ক্ষেত্রে আপনার খুব সতর্ক থাকা উচিত। কম্পাইলারের আচরণকে অগ্রাহ্য করলে অপ্রত্যাশিত বাগ দেখা দিতে পারে, যেমন—আপনার প্রত্যাশা অনুযায়ী কম্পোজেবলটি রিকম্পোজ না হওয়া।
যদি কোনো অ্যানোটেশন ছাড়া আপনার ক্লাসকে স্থিতিশীল করা সম্ভব হয়, তবে আপনার সেইভাবেই স্থিতিশীলতা অর্জনের চেষ্টা করা উচিত।
নিম্নলিখিত কোড স্নিপেটটি অপরিবর্তনীয় (immutable) হিসেবে টীকাযুক্ত একটি ডেটা ক্লাসের সংক্ষিপ্ত উদাহরণ প্রদান করে:
@Immutable
data class Snack(
…
)
আপনি @Immutable বা @Stable অ্যানোটেশন ব্যবহার করুন না কেন, Compose কম্পাইলার Snack ক্লাসটিকে স্থিতিশীল (stable) হিসেবে চিহ্নিত করে।
সংগ্রহে টীকাযুক্ত ক্লাস
এমন একটি কম্পোজেবল বিবেচনা করুন যাতে List<Snack> টাইপের একটি প্যারামিটার অন্তর্ভুক্ত রয়েছে:
restartable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
…
unstable snacks: List<Snack>
…
)
আপনি Snack @Immutable দিয়ে টীকাযুক্ত করলেও, Compose কম্পাইলার HighlightedSnacks এর snacks প্যারামিটারটিকে অস্থিতিশীল হিসেবে চিহ্নিত করে।
কালেকশন টাইপের ক্ষেত্রে প্যারামিটারগুলোও ক্লাসের মতোই একই সমস্যার সম্মুখীন হয়; কম্পোজ কম্পাইলার সবসময় List টাইপের একটি প্যারামিটারকে আনস্টেবল (unstable) হিসেবে চিহ্নিত করে , এমনকি যখন সেটি স্টেবল (stable) টাইপের একটি কালেকশন হয়।
আপনি কোনো স্বতন্ত্র প্যারামিটারকে স্থিতিশীল হিসেবে চিহ্নিত করতে পারবেন না, কিংবা কোনো কম্পোজেবলকে সর্বদা এড়িয়ে যাওয়ার জন্য টীকাও দিতে পারবেন না। সামনে এগোনোর একাধিক পথ রয়েছে।
অস্থিতিশীল সংগ্রহের সমস্যাটি এড়ানোর বিভিন্ন উপায় রয়েছে। নিম্নলিখিত উপবিভাগগুলিতে এই বিভিন্ন পন্থাগুলো তুলে ধরা হয়েছে।
কনফিগারেশন ফাইল
আপনি যদি আপনার কোডবেসে স্থিতিশীলতার চুক্তি মেনে চলতে ইচ্ছুক হন, তাহলে আপনার স্থিতিশীলতা কনফিগারেশন ফাইলে kotlin.collections.* যোগ করে কোটলিন কালেকশনগুলোকে স্থিতিশীল হিসেবে বিবেচনা করার বিকল্পটি বেছে নিতে পারেন।
অপরিবর্তনীয় সংগ্রহ
অপরিবর্তনীয়তার কম্পাইল-টাইম সুরক্ষার জন্য, আপনি List এর পরিবর্তে একটি কোটলিনক্স অপরিবর্তনীয় কালেকশন ব্যবহার করতে পারেন।
@Composable
private fun HighlightedSnacks(
…
snacks: ImmutableList<Snack>,
…
)
মোড়ক
যদি আপনি একটি অপরিবর্তনশীল কালেকশন ব্যবহার করতে না পারেন, তবে আপনি নিজেরটা তৈরি করে নিতে পারেন। এর জন্য, List একটি অ্যানোটেড স্টেবল ক্লাসের মধ্যে র্যাপ করুন। আপনার প্রয়োজনের উপর নির্ভর করে, এর জন্য একটি জেনেরিক র্যাপার সম্ভবত সেরা বিকল্প হবে।
@Immutable
data class SnackCollection(
val snacks: List<Snack>
)
এরপর আপনি এটিকে আপনার কম্পোজেবলের প্যারামিটারের টাইপ হিসেবে ব্যবহার করতে পারবেন।
@Composable
private fun HighlightedSnacks(
index: Int,
snacks: SnackCollection,
onSnackClick: (Long) -> Unit,
modifier: Modifier = Modifier
)
সমাধান
এই পদ্ধতিগুলোর যেকোনো একটি অনুসরণ করার পর, Compose কম্পাইলার এখন HighlightedSnacks Composable-টিকে skippable এবং restartable উভয় হিসেবেই চিহ্নিত করে।
restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
stable index: Int
stable snacks: ImmutableList<Snack>
stable onSnackClick: Function1<Long, Unit>
stable modifier: Modifier? = @static Companion
)
পুনর্গঠনের সময়, যদি HighlightedSnacks এর কোনো ইনপুট পরিবর্তিত না হয়, তাহলে Compose এখন এটিকে এড়িয়ে যেতে পারে।
স্থিতিশীলতা কনফিগারেশন ফাইল
কম্পোজ কম্পাইলার ১.৫.৫ থেকে শুরু করে, কোন ক্লাসগুলোকে স্থিতিশীল (stable) হিসেবে বিবেচনা করা হবে তার একটি কনফিগারেশন ফাইল কম্পাইল করার সময় প্রদান করা যায়। এর ফলে, আপনার নিয়ন্ত্রণে নেই এমন ক্লাসগুলোকেও, যেমন LocalDateTime এর মতো স্ট্যান্ডার্ড লাইব্রেরির ক্লাসগুলোকে, স্থিতিশীল হিসেবে বিবেচনা করা যায়।
কনফিগারেশন ফাইলটি একটি সাধারণ টেক্সট ফাইল, যেখানে প্রতিটি সারিতে একটি করে ক্লাস থাকে। এতে মন্তব্য, একক এবং দ্বৈত ওয়াইল্ডকার্ড সমর্থিত।
একটি উদাহরণ কনফিগারেশন:
// Consider LocalDateTime stable
java.time.LocalDateTime
// Consider my datalayer stable
com.datalayer.*
// Consider my datalayer and all submodules stable
com.datalayer.**
// Consider my generic type stable based off it's first type parameter only
com.example.GenericClass<*,_>
এই বৈশিষ্ট্যটি সক্রিয় করতে, কম্পোজ কম্পাইলার গ্র্যাডল প্লাগইন কনফিগারেশনের ` composeCompiler অপশন ব্লকে কনফিগারেশন ফাইলের পাথটি পাস করুন।
composeCompiler {
stabilityConfigurationFile = rootProject.layout.projectDirectory.file("stability_config.conf")
}
যেহেতু কম্পোজ কম্পাইলার আপনার প্রোজেক্টের প্রতিটি মডিউলে আলাদাভাবে চলে, তাই প্রয়োজনে আপনি বিভিন্ন মডিউলে ভিন্ন ভিন্ন কনফিগারেশন দিতে পারেন। বিকল্পভাবে, আপনার প্রোজেক্টের রুট লেভেলে একটি কনফিগারেশন রাখুন এবং সেই পাথটি প্রতিটি মডিউলে পাস করুন।
একাধিক মডিউল
আরেকটি সাধারণ সমস্যা হলো মাল্টি-মডিউল আর্কিটেকচার। কম্পোজ কম্পাইলার কেবল তখনই কোনো ক্লাস স্থিতিশীল কিনা তা অনুমান করতে পারে, যখন সেই ক্লাস দ্বারা রেফারেন্সকৃত সমস্ত নন-প্রিমিটিভ টাইপ হয় স্পষ্টভাবে স্থিতিশীল হিসাবে চিহ্নিত থাকে অথবা এমন কোনো মডিউলে থাকে যা কম্পোজ কম্পাইলার দিয়েই বিল্ড করা হয়েছে।
যদি আপনার ডেটা লেয়ারটি UI লেয়ার থেকে একটি আলাদা মডিউলে থাকে, যা একটি প্রস্তাবিত পদ্ধতি, তাহলে আপনি এই সমস্যার সম্মুখীন হতে পারেন।
সমাধান
এই সমস্যাটি সমাধান করতে আপনি নিম্নলিখিত পদ্ধতিগুলোর মধ্যে যেকোনো একটি অবলম্বন করতে পারেন:
- আপনার কম্পাইলার কনফিগারেশন ফাইলে ক্লাসগুলো যোগ করুন।
- আপনার ডেটা লেয়ার মডিউলগুলিতে কম্পোজ কম্পাইলার সক্রিয় করুন, অথবা যেখানে প্রয়োজন সেখানে আপনার ক্লাসগুলিকে
@Stableবা@Immutableদিয়ে ট্যাগ করুন।- এর জন্য আপনার ডেটা লেয়ারে একটি Compose ডিপেন্ডেন্সি যোগ করতে হবে। তবে, এটি শুধুমাত্র Compose রানটাইমের জন্য ডিপেন্ডেন্সি,
Compose-UIজন্য নয়।
- এর জন্য আপনার ডেটা লেয়ারে একটি Compose ডিপেন্ডেন্সি যোগ করতে হবে। তবে, এটি শুধুমাত্র Compose রানটাইমের জন্য ডিপেন্ডেন্সি,
- আপনার UI মডিউলের মধ্যে, আপনার ডেটা লেয়ার ক্লাসগুলোকে UI-নির্দিষ্ট র্যাপার ক্লাসের মধ্যে রাখুন।
এক্সটার্নাল লাইব্রেরিগুলো যদি কম্পোজ কম্পাইলার ব্যবহার না করে, তাহলে সেগুলো ব্যবহার করার ক্ষেত্রেও একই সমস্যা দেখা দেয়।
প্রতিটি রচনাযোগ্য জিনিস এড়িয়ে যাওয়া উচিত নয়।
স্থিতিশীলতার সমস্যা সমাধানের জন্য কাজ করার সময়, প্রতিটি কম্পোজেবলকে স্কিপেবল করার চেষ্টা করা উচিত নয়। এমনটা করার চেষ্টা করলে অকাল অপ্টিমাইজেশন হতে পারে, যা সমস্যার সমাধানের চেয়ে আরও বেশি সমস্যা তৈরি করে।
এমন অনেক পরিস্থিতি আছে যেখানে স্কিপেবল হওয়ার কোনো বাস্তব সুবিধা নেই এবং এর ফলে এমন কোড তৈরি হতে পারে যা রক্ষণাবেক্ষণ করা কঠিন হয়ে পড়ে। উদাহরণস্বরূপ:
- এমন একটি রচনাযোগ্য উপাদান যা সচরাচর পুনর্গঠিত হয় না, বা একেবারেই হয় না।
- একটি কম্পোজেবল যা নিজে থেকেই স্কিপেবল কম্পোজেবলগুলোকে কল করে।
- একটি কম্পোজেবল ফাংশন যার অনেকগুলো প্যারামিটার আছে এবং যার ইকুয়ালস ইমপ্লিমেন্টেশনগুলো ব্যয়বহুল। এক্ষেত্রে, কোনো প্যারামিটার পরিবর্তিত হয়েছে কিনা তা পরীক্ষা করার খরচ একটি সস্তা রিকম্পোজিশনের খরচকে ছাড়িয়ে যেতে পারে।
যখন কোনো কম্পোজেবল স্কিপেবল হয়, তখন এটি একটি সামান্য ওভারহেড যোগ করে যা হয়তো লাভজনক নয়। এমনকি আপনি আপনার কম্পোজেবলকে নন-রিস্টার্টেবল হিসেবেও অ্যানোটেট করতে পারেন, যদি আপনার মনে হয় যে রিস্টার্টেবল হওয়াটা তার উপযোগিতার চেয়ে বেশি ওভারহেড তৈরি করে।