পারফর্ম্যান্স সংক্রান্ত সমস্যা সৃষ্টি করে এমন অস্থির ক্লাস-এর সম্মুখীন হলে, আপনাকে এটি স্থির করতে হবে। এই ডকুমেন্টে এমন কিছু কৌশল উল্লেখ করা হয়েছে যা আপনি এই কাজে ব্যবহার করতে পারেন।
স্ট্রং স্কিপিং চালু করুন
প্রথমে আপনাকে স্ট্রং স্কিপিং মোড চালু করার চেষ্টা করতে হবে। স্ট্রং স্কিপিং মোড, অস্থির প্যারামিটার সহ কম্পোজ করার উপযুক্ত আইটেমকে এড়িয়ে যেতে দেয় এবং এটি হল স্থায়িত্বের কারণে হওয়া পারফর্ম্যান্স সংক্রান্ত সমস্যা সমাধান করার সবচেয়ে সহজ পদ্ধতি।
আরও তথ্যের জন্য স্ট্রং স্কিপিং দেখুন।
ক্লাসটি অপরিবর্তনীয় করুন
এছাড়াও, আপনি কোনও অস্থির ক্লাসকে সম্পূর্ণ অপরিবর্তনীয় করার চেষ্টা করতে পারেন।
- পরিবর্তনযোগ্য নয়: এমন একটি ধরনকে বোঝায় যেখানে সেই ধরনের কোনও ইনস্ট্যান্স তৈরি হওয়ার পরে কোনও প্রপার্টির মান কখনও
পরিবর্তন করা যায় না এবং সমস্ত পদ্ধতিই
রেফারেন্সিয়ালি ট্রান্সপারেন্ট হয়।
- নিশ্চিত করুন যে ক্লাসের সব প্রপার্টি
var-এর পরিবর্তেvalএবং অপরিবর্তনীয় ধরনের। String, IntএবংFloat-এর মতো প্রিমিটিভ টাইপ সবসময় অপরিবর্তনীয় হয়।- এটি সম্ভব না হলে, আপনাকে অবশ্যই যেকোনও পরিবর্তনযোগ্য প্রপার্টির জন্য কম্পোজ স্টেট ব্যবহার করতে হবে।
- নিশ্চিত করুন যে ক্লাসের সব প্রপার্টি
- Stable: এমন ধরনকে নির্দেশ করে যা পরিবর্তনযোগ্য। Compose রানটাইম জানতে পারে না যে কখন এবং কীভাবে কোনও ধরনের পাবলিক প্রপার্টি বা মেথড আচরণ আগের ইনভোকেশন থেকে আলাদা ফলাফল দেবে।
অপরিবর্তনীয় কালেকশন
Compose কোনও ক্লাসকে আনস্টেবল হিসেবে বিবেচনা করার একটি সাধারণ কারণ হল কালেকশন। স্টেবিলিটি সংক্রান্ত সমস্যা ডায়াগনসিস করা পৃষ্ঠায়
যেমন উল্লেখ করা হয়েছে, Compose কম্পাইলার
List, Map ও Set-এর মতো কালেকশন সত্যিই অপরিবর্তনীয় কিনা সেই ব্যাপারে
সম্পূর্ণ নিশ্চিত হতে পারে না এবং তাই সেগুলিকে আনস্টেবল হিসেবে চিহ্নিত করে।
এর সমাধান করতে, আপনি অপরিবর্তনীয় কালেকশন ব্যবহার করতে পারেন। Compose কম্পাইলারে Kotlinx Immutable Collections-এর জন্য সহায়তা অন্তর্ভুক্ত আছে। এই কালেকশনগুলি অপরিবর্তনীয় হওয়ার জন্য ডিজাইন করা হয়েছে এবং Compose কম্পাইলার সেগুলিকে সেইভাবেই বিবেচনা করে। এই লাইব্রেরি এখনও আলফা ভার্সনে আছে, তাই এর API-তে সম্ভাব্য পরিবর্তন হতে পারে।
স্টেবিলিটি সংক্রান্ত সমস্যা ডায়াগনসিস করুন গাইড থেকে এই অস্থির ক্লাসটি আবার বিবেচনা করুন:
unstable class Snack {
…
unstable val tags: Set<String>
…
}
আপনি অপরিবর্তনীয় সংগ্রহ ব্যবহার করে tags স্থিতিশীল করতে পারবেন। ক্লাসে, tags-এর ধরন পরিবর্তন করে ImmutableSet<String> করুন:
data class Snack{
…
val tags: ImmutableSet<String> = persistentSetOf()
…
}
এটি করার পরে, ক্লাসের সব প্যারামিটার অপরিবর্তনীয় হয়ে যায় এবং Compose কম্পাইলার ক্লাসটিকে স্টেবল হিসেবে চিহ্নিত করে।
Stable বা Immutable-এর মাধ্যমে অ্যানোটেট করা
স্থায়িত্ব সংক্রান্ত সমস্যার সমাধান করার একটি সম্ভাব্য উপায় হল @Stable বা @Immutable-এর মাধ্যমে
অস্থায়ী ক্লাস অ্যানোটেট করা।
কোনও ক্লাসকে অ্যানোটেট করা মানে, কম্পাইলার আপনার ক্লাস সম্পর্কে অন্যথায় যা কিছু
অনুমান করত, তা ওভাররাইড করা। এটি Kotlin-এর
!! অপারেটরের মতো। এইসব অ্যানোটেশন কীভাবে ব্যবহার করবেন
সেই ব্যাপারে আপনাকে খুব সতর্ক থাকতে হবে। কম্পাইলারের আচরণ ওভাররাইড করলে
আপনি অপ্রত্যাশিত সমস্যার সম্মুখীন হতে পারেন, যেমন আপনার কম্পোজেবল আপনার প্রত্যাশা অনুযায়ী
পুনরায় কম্পোজ না হওয়া।
অ্যানোটেশন ছাড়াই আপনার ক্লাস স্থিতিশীল করা সম্ভব হলে, আপনাকে সেইভাবে স্থিতিশীলতা অর্জন করার চেষ্টা করতে হবে।
নিচের স্নিপেটে পরিবর্তনযোগ্য নয় হিসেবে অ্যানোটেট করা ডেটা ক্লাসের একটি ন্যূনতম উদাহরণ দেওয়া হয়েছে:
@Immutable
data class Snack(
…
)
আপনি @Immutable বা @Stable অ্যানোটেশন ব্যবহার করুন না কেন, Compose কম্পাইলার
Snack ক্লাসকে স্টেবল হিসেবে চিহ্নিত করে।
সংগ্রহে অ্যানোটেট করা ক্লাস
এমন একটি কম্পোজেবল বিবেচনা করুন যাতে List<Snack> ধরনের প্যারামিটার অন্তর্ভুক্ত থাকে:
restartable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
…
unstable snacks: List<Snack>
…
)
এমনকি আপনি @Immutable-এর সাথে Snack অ্যানোটেট করলেও, Compose কম্পাইলার এখনও
HighlightedSnacks-এর snacks প্যারামিটারকে আনস্টেবল হিসেবে চিহ্নিত করে।
কালেকশন টাইপের ক্ষেত্রে প্যারামিটারগুলি ক্লাসের মতোই সমস্যার সম্মুখীন হয়,
Compose কম্পাইলার সবসময় List টাইপের একটি প্যারামিটারকে অস্থির হিসেবে চিহ্নিত করে, এমনকি
যখন এটি স্থিতিশীল টাইপের একটি কালেকশন হয়।
আপনি কোনও স্বতন্ত্র প্যারামিটারকে স্টেবল হিসেবে চিহ্নিত করতে পারবেন না, অথবা আপনি কোনও কম্পোজেবলকে সবসময় এড়িয়ে যাওয়ার যোগ্য হিসেবে অ্যানোটেট করতে পারবেন না। এগিয়ে যাওয়ার জন্য একাধিক পথ রয়েছে।
অস্থির সংগ্রহের সমস্যা থেকে মুক্তি পাওয়ার জন্য আপনি বিভিন্ন উপায় অবলম্বন করতে পারেন। নিম্নলিখিত উপবিভাগে এইসব বিভিন্ন পদ্ধতির ব্যাপারে বর্ণনা করা হয়েছে।
কনফিগারেশন ফাইল
আপনার কোডবেসে স্থিতিশীলতা সংক্রান্ত চুক্তি মেনে চলতে কোনও অসুবিধা না থাকলে, আপনি
স্থিতিশীলতা কনফিগারেশন
ফাইলে kotlin.collections.* যোগ করে Kotlin কালেকশনকে স্থিতিশীল হিসেবে বিবেচনা করার
বিকল্প বেছে নিতে পারেন।
অপরিবর্তনীয় সংগ্রহ
পরিবর্তনযোগ্যতা সংক্রান্ত কম্পাইল টাইম সুরক্ষার জন্য, আপনি List-এর পরিবর্তে kotlinx পরিবর্তনযোগ্য
সংগ্রহ ব্যবহার করতে পারেন।
@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
)
রিকম্পোজিশনের সময়, Compose এখন HighlightedSnacks এড়িয়ে যেতে পারে যদি এর কোনও
ইনপুট পরিবর্তন না হয়ে থাকে।
স্টেবিলিটি কনফিগারেশন ফাইল
Compose Compiler 1.5.5 থেকে শুরু করে, কম্পাইল করার সময় স্থিতিশীল হিসেবে বিবেচনা করার জন্য ক্লাসের একটি কনফিগারেশন ফাইল
প্রদান করা যেতে পারে। এটি আপনাকে
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<*,_>
এই ফিচার চালু করতে, কনফিগারেশন ফাইলের পাথ Compose কম্পাইলার Gradle প্লাগ-ইন
কনফিগারেশনের composeCompiler বিকল্প ব্লকে পাস করুন।
composeCompiler {
stabilityConfigurationFile = rootProject.layout.projectDirectory.file("stability_config.conf")
}
Compose কম্পাইলার আপনার প্রোজেক্টের প্রতিটি মডিউলে আলাদাভাবে রান করে, তাই আপনি প্রয়োজন হলে বিভিন্ন মডিউলে বিভিন্ন কনফিগারেশন প্রদান করতে পারবেন। অন্যথায়, আপনার প্রোজেক্টের রুট লেভেলে একটি কনফিগারেশন রাখুন এবং সেই পাথ প্রতিটি মডিউলে পাস করুন।
একাধিক মডিউল
মাল্টি-মডিউল আর্কিটেকচার সংক্রান্ত সমস্যাও প্রায়ই দেখা যায়। Compose কম্পাইলার কোনও ক্লাস স্থিতিশীল কিনা তা তখনই বুঝতে পারে যদি সেটির রেফারেন্স করা সব নন-প্রিমিটিভ টাইপ স্পষ্টভাবে স্থিতিশীল হিসেবে চিহ্নিত করা থাকে অথবা এমন মডিউলে থাকে যেটি Compose কম্পাইলারের সাহায্যেও তৈরি করা হয়েছে।
আপনার ডেটা লেয়ার যদি UI লেয়ার থেকে আলাদা মডিউলে থাকে, যা হল প্রস্তাবিত পদ্ধতি, তাহলে আপনি এই সমস্যার সম্মুখীন হতে পারেন।
সমাধান
এই সমস্যার সমাধান করতে, আপনি নিম্নলিখিত পদ্ধতিগুলির মধ্যে একটি ব্যবহার করতে পারেন:
- আপনার কম্পাইলার কনফিগারেশন ফাইলে ক্লাস যোগ করুন।
- আপনার ডেটা লেয়ার মডিউলে Compose কম্পাইলার চালু করুন অথবা যেখানে উপযুক্ত সেখানে
@Stableবা@Immutableদিয়ে আপনার ক্লাস ট্যাগ করুন।- এর মধ্যে আপনার ডেটা লেয়ারে একটি কম্পোজ ডিপেন্ডেন্সি যোগ করা অন্তর্ভুক্ত। তবে,
এটি শুধুমাত্র Compose রানটাইমের উপর নির্ভরশীল এবং
Compose-UI-এর উপর নয়।
- এর মধ্যে আপনার ডেটা লেয়ারে একটি কম্পোজ ডিপেন্ডেন্সি যোগ করা অন্তর্ভুক্ত। তবে,
এটি শুধুমাত্র Compose রানটাইমের উপর নির্ভরশীল এবং
- আপনার UI মডিউলের মধ্যে, UI-নির্দিষ্ট র্যাপার ক্লাসে আপনার ডেটা লেয়ার ক্লাস র্যাপ করুন।
এক্সটার্নাল লাইব্রেরি ব্যবহার করার সময়ও একই সমস্যা হয়, যদি সেগুলি Compose কম্পাইলার ব্যবহার না করে।
প্রতিটি কম্পোজেবল এড়িয়ে যাওয়া যাবে না
স্থিতিশীলতা সংক্রান্ত সমস্যা সমাধানের সময়, আপনাকে প্রতিটি কম্পোজ করার মতো স্কিপ করার চেষ্টা করা উচিত নয়। এটি করার চেষ্টা করলে অকাল অপ্টিমাইজেশন হতে পারে যা সমস্যার সমাধান করার চেয়ে আরও বেশি সমস্যা তৈরি করে।
এমন অনেক পরিস্থিতি আছে যেখানে স্কিপেবল হওয়ার কোনও বাস্তব সুবিধা নেই এবং কোড বজায় রাখা কঠিন হতে পারে। যেমন:
- এমন কম্পোজ করার উপযুক্ত আইটেম যা প্রায়ই বা কখনওই আবার কম্পোজ করা হয় না।
- এমন একটি কম্পোজ করার মতো আইটেম যা নিজেই শুধু এড়িয়ে যাওয়ার মতো কম্পোজ করার মতো আইটেমকে কল করে।
- কম্পোজ করার উপযুক্ত এমন একটি আইটেম যাতে অনেক প্যারামিটার সহ ব্যয়বহুল equals ইমপ্লিমেন্টেশন আছে। এই ক্ষেত্রে, কোনও প্যারামিটার পরিবর্তন হয়েছে কিনা তা চেক করার খরচ সস্তা রিকম্পোজিশনের খরচের চেয়ে বেশি হতে পারে।
কোনও কম্পোজেবল এড়িয়ে যাওয়ার মতো হলে, এটি একটি ছোট ওভারহেড যোগ করে যা হয়ত উপযুক্ত নয়। এমনকি আপনি নিজের কম্পোজেবলকে রিস্টার্ট করা যাবে না হিসেবে অ্যানোটেট করতে পারেন, যেখানে আপনি নির্ধারণ করেন যে রিস্টার্ট করা যাবে এমন কম্পোজেবল ব্যবহার করা বেশি ওভারহেড।