Compose-এ স্থিতিশীলতা

Compose-এ টাইপকে স্থিতিশীল বা অস্থিতিশীল হিসেবে বিবেচনা করা হয়। কোনও টাইপ তখনই স্টেবল হয় যখন সেটি অপরিবর্তনীয় হয় অথবা কম্পোজিশনের মধ্যে সেটির ভ্যালু পরিবর্তিত হয়েছে কিনা তা Compose-এর পক্ষে জানা সম্ভব হয়। কোনও টাইপকে তখনই অস্থির বলা হয় যখন Compose বুঝতে পারে না যে রিকম্পোজিশনের মধ্যে এর ভ্যালু পরিবর্তন হয়েছে কিনা।

কম্পোজ, কম্পোজেবলের প্যারামিটারের স্থায়িত্ব ব্যবহার করে নির্ধারণ করে যে কীভাবে ইনপুট তুলনা করতে হবে এবং রিকম্পোজিশন (Kotlin 2.0.20 থেকে ডিফল্ট হিসেবে স্ট্রং স্কিপিং মোড চালু করা সহ) চলাকালীন কম্পোজেবল এড়িয়ে যেতে পারবে কিনা তা সিদ্ধান্ত নেয়:

  • স্টেবল প্যারামিটার: Compose স্ট্রাকচারাল ইকুয়ালিটি (Object.equals()) ব্যবহার করে স্টেবল প্যারামিটার তুলনা করে। কোনও কম্পোজেবলের স্টেবল প্যারামিটার আগের ভ্যালুর সমান হলে, Compose সেটি স্কিপ করে যায়।
  • অস্থির প্যারামিটার: স্ট্রং স্কিপিং মোড চালু থাকলে (Kotlin 2.0.20 এবং তার পরবর্তী ভার্সনে ডিফল্ট), Compose ইনস্ট্যান্স ইকুয়ালিটি (===) ব্যবহার করে অস্থির প্যারামিটার তুলনা করে এবং একই অবজেক্ট ইনস্ট্যান্স পাস করা হলে কম্পোজেবল স্কিপ করে। Kotlin 2.0.20-এর আগের ভার্সনে (অথবা যখন স্ট্রং স্কিপিং মোড বন্ধ করা থাকে), কম্পোজ সবসময় আনস্টেবল প্যারামিটার সহ কম্পোজেবলকে রিকম্পোজ করে যখন তার পেরেন্ট রিকম্পোজ করে।

আপনার অ্যাপ যদি ঘন ঘন অস্থির প্যারামিটারের নতুন ইনস্ট্যান্স বরাদ্দ করে—অথবা মডেলগুলিকে অতিরিক্ত অ্যানোটেট করে বড় কালেকশনে ব্যয়বহুল .equals() চেক করতে বাধ্য করে—তাহলে আপনি অপ্রয়োজনীয় রিকম্পোজিশন বা তুলনা ওভারহেড লক্ষ্য করতে পারেন।

এই ডকুমেন্ট থেকে আপনি জানতে পারবেন যে Compose কীভাবে স্থায়িত্ব নির্ধারণ করে এবং পারফর্ম্যান্স ও সামগ্রিক ব্যবহারকারীর অভিজ্ঞতা উন্নত করতে আপনি কীভাবে এটি অপ্টিমাইজ করতে পারেন।

অপরিবর্তনীয় অবজেক্ট

নিম্নলিখিত স্নিপেটগুলি স্থিতিশীলতা এবং রিকম্পোজিশনের পিছনে সাধারণ নীতিগুলি প্রদর্শন করে।

Contact ক্লাস হল একটি অপরিবর্তনীয় ডেটা ক্লাস। কারণ, এর সব প্যারামিটার হল val কীওয়ার্ড দিয়ে সংজ্ঞায়িত প্রিমিটিভ। আপনি একবার Contact-এর ইনস্ট্যান্স তৈরি করলে, অবজেক্টের প্রপার্টির ভ্যালু পরিবর্তন করতে পারবেন না। আপনি যদি তা করার চেষ্টা করেন, তাহলে আপনি একটি নতুন অবজেক্ট তৈরি করবেন।

data class Contact(val name: String, val number: String)

ContactRow কম্পোজেবলে Contact ধরনের প্যারামিটার আছে।

@Composable
fun ContactRow(contact: Contact, modifier: Modifier = Modifier) {
   var selected by remember { mutableStateOf(false) }

   Row(modifier) {
      ContactDetails(contact)
      ToggleButton(selected, onToggled = { selected = !selected })
   }
}

ব্যবহারকারী টগল বোতামে ক্লিক করলে কী হয় এবং selected স্ট্যাটাস পরিবর্তন হয় কিনা তা বিবেচনা করুন:

  1. Compose মূল্যায়ন করে দেখে যে ContactRow-এর মধ্যে থাকা কোড আবার কম্পোজ করা উচিত কিনা।
  2. এটি দেখে যে ContactDetails-এর জন্য একমাত্র আর্গুমেন্ট Contact ধরনের।
  3. যেহেতু Contact হল একটি অপরিবর্তনীয় ডেটা ক্লাস, তাই Compose নিশ্চিত যে ContactDetails-এর কোনও আর্গুমেন্ট পরিবর্তন হয়নি।
  4. তাই, Compose ContactDetails এড়িয়ে যায় এবং এটি আবার কম্পোজ করে না।
  5. অন্যদিকে, ToggleButton-এর আর্গুমেন্ট পরিবর্তন হয়েছে এবং Compose সেই কম্পোনেন্ট আবার কম্পোজ করে।

পরিবর্তনযোগ্য অবজেক্ট

পূর্ববর্তী উদাহরণে একটি অপরিবর্তনীয় অবজেক্ট ব্যবহার করা হলেও, একটি পরিবর্তনশীল অবজেক্ট তৈরি করা সম্ভব। নিম্নলিখিত স্নিপেটটি বিবেচনা করুন:

data class Contact(var name: String, var number: String)

Contact-এর প্রতিটি প্যারামিটার এখন var হওয়ায়, ক্লাসটি আর অপরিবর্তনীয় নয়। এর প্রপার্টি পরিবর্তন হলে, Compose তা জানতে পারবে না। এর কারণ হল, Compose শুধুমাত্র Compose স্টেট অবজেক্টে করা পরিবর্তন ট্র্যাক করে।

Compose এই ধরনের ক্লাসকে অস্থির হিসেবে বিবেচনা করে। স্ট্রং স্কিপিং মোড (Kotlin 2.0.20+)-এর সাথে, Compose ইনস্ট্যান্স ইকুয়ালিটি (===) ব্যবহার করে Contact তুলনা করে: contact.name-কে মিউটেট করলে রিকম্পোজিশন ট্রিগার হবে না, তবে একই ভ্যালু সহ নতুন বরাদ্দ করা Contact ইনস্ট্যান্স পাস করলে, ContactDetails-কে রিকম্পোজ করতে বাধ্য করবে (এবং স্ট্রং স্কিপিং মোড ছাড়া, selected পরিবর্তন হলেই ContactDetails রিকম্পোজ করে)।

Compose-এ প্রয়োগ

রিকম্পোজিশনের সময় কোন ফাংশন এড়িয়ে যেতে হবে তা Compose কীভাবে নির্ধারণ করে তা বিবেচনা করা সহায়ক হতে পারে, যদিও তা গুরুত্বপূর্ণ নয়।

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

অপেক্ষক

Compose, ফাংশনকে skippable বা restartable হিসেবে চিহ্নিত করতে পারে। মনে রাখবেন যে এটি কোনও ফাংশনকে এর মধ্যে একটি, দুটি বা কোনওটিই নয় হিসেবে চিহ্নিত করতে পারে:

  • এড়িয়ে যাওয়া যায়: কম্পাইলার কোনও কম্পোজেবলকে এড়িয়ে যাওয়া যায় হিসেবে চিহ্নিত করলে, রিকম্পোজিশনের সময় Compose সেটি এড়িয়ে যেতে পারে, যদি তার সব আর্গুমেন্ট আগের ভ্যালুর সাথে মিলে যায়। (Kotlin 2.0.20+ ভার্সনে স্ট্রং স্কিপিং মোড সহ, সব রিস্টার্ট করা যায় এমন কম্পোজেবল অটোমেটিক স্কিপ করা যায়।)
  • রিস্টার্ট করা যায়: রিস্টার্ট করা যায় এমন কম্পোজেবল "স্কোপ" হিসেবে কাজ করে যেখানে রিকম্পোজিশন শুরু করা যায়। অন্যভাবে বলতে গেলে, এই ফাংশনটি এমন একটি এন্ট্রি পয়েন্ট হতে পারে যেখান থেকে Compose, স্টেট পরিবর্তনের পরে রিকম্পোজিশনের জন্য কোড আবার এক্সিকিউট করা শুরু করতে পারে।

ধরন

Compose, টাইপকে অপরিবর্তনীয় বা স্থিতিশীল হিসেবে চিহ্নিত করে। প্রতিটি ধরন হল একটি বা অন্যটি:

  • ইমিউটেবল: Compose কোনও ধরনকে ইমিউটেবল হিসেবে চিহ্নিত করে যদি তার প্রপার্টির ভ্যালু কখনও পরিবর্তন করা না যায় এবং সব পদ্ধতি রেফারেন্সিয়ালি ট্রান্সপারেন্ট হয়।
    • মনে রাখবেন যে সব প্রিমিটিভ টাইপ অপরিবর্তনীয় হিসেবে চিহ্নিত করা হয়। এর মধ্যে String, Int এবং Float অন্তর্ভুক্ত।
  • Stable: এমন একটি ধরনকে নির্দেশ করে যার প্রপার্টি কনস্ট্রাকশনের পরে পরিবর্তন হতে পারে। রানটাইমের সময় যদি এবং যখন সেইসব প্রপার্টি পরিবর্তন হয়, Compose সেইসব পরিবর্তন সম্পর্কে সচেতন হয়।

ডিবাগ স্টেবিলিটি

আপনার অ্যাপ যদি এমন কোনও কম্পোজ করার মতো আইটেম আবার কম্পোজ করে যার প্যারামিটার পরিবর্তন হয়নি, তাহলে প্রথমে চেক করে দেখুন যে প্রতিটি রিকম্পোজিশনে (অথবা, স্ট্রং স্কিপিং মোড বন্ধ করা থাকলে, কম্পোজ করার মতো আইটেমে var প্রপার্টি বা আনস্টেবল টাইপের val প্রপার্টি সহ প্যারামিটার থাকলে) আনস্টেবল টাইপের নতুন ইনস্ট্যান্স বরাদ্দ করা হচ্ছে কিনা।

Compose-এ স্টেবিলিটি সংক্রান্ত জটিল সমস্যা কীভাবে ডায়াগনসিস করবেন সেই সম্পর্কে বিস্তারিত তথ্যের জন্য, ডিবাগ স্টেবিলিটি নির্দেশিকা দেখুন।

স্থায়িত্ব সংক্রান্ত সমস্যার সমাধান করা

আপনার Compose ইমপ্লিমেন্টেশনে কীভাবে স্টেবিলিটি আনবেন সেই সম্পর্কে তথ্য পেতে, স্টেবিলিটি সংক্রান্ত সমস্যার সমাধান করুন গাইড দেখুন।

সারাংশ

সামগ্রিকভাবে, আপনাকে নিম্নলিখিত বিষয়গুলি মনে রাখতে হবে:

  • প্যারামিটার: রিকম্পোজিশনের সময় স্ট্রাকচারাল ইকুয়ালিটি (.equals()) নাকি ইনস্ট্যান্স ইকুয়ালিটি (===) ব্যবহার করে কম্পেয়ার করা হবে তা নির্ধারণ করার জন্য, Compose আপনার কম্পোজেবলের প্রতিটি প্যারামিটারের স্টেবিলিটি নির্ধারণ করে।
  • অবিলম্বে সমাধান: আপনি যদি লক্ষ্য করেন যে আপনার কম্পোজেবল এড়ানো হচ্ছে না এবং এটি পারফর্ম্যান্স সংক্রান্ত সমস্যা সৃষ্টি করছে, তাহলে প্রতিটি পাসে অস্থির প্যারামিটারের নতুন ইনস্ট্যান্স আবার তৈরি করা হচ্ছে কিনা বা State-এর পরিবর্তে var প্রপার্টি ব্যবহার করা হচ্ছে কিনা তা চেক করুন।
  • কম্পাইলার রিপোর্ট: আপনার ক্লাস সম্পর্কে কী ধরনের স্টেবিলিটি অনুমান করা হচ্ছে তা নির্ধারণ করতে, আপনি কম্পাইলার রিপোর্ট ব্যবহার করতে পারেন।
  • কালেকশন: Compose স্ট্যান্ডার্ড কালেকশন ইন্টারফেসকে (List, Set এবং Map) অস্থির হিসেবে বিবেচনা করে কারণ তাদের অন্তর্নিহিত বাস্তবায়ন পরিবর্তনযোগ্য হতে পারে। স্ট্রং স্কিপিং মোড (Kotlin 2.0.20+ ভার্সনে ডিফল্ট হিসেবে চালু করা থাকে) ব্যবহার করে, কালেকশন রেফারেন্স পরিবর্তন না হলে, ইনস্ট্যান্স ইকুয়ালিটি (===) ব্যবহার করে অস্থির কালেকশন এখনও রিকম্পোজিশন স্কিপ করে। Kotlinx ইমিউটেবল কালেকশন দিয়ে স্ট্যান্ডার্ড কালেকশন রিপ্লেস করার সময় অথবা @Immutable বা @Stable দিয়ে কালেকশন-হোল্ডিং ক্লাস অ্যানোটেট করার সময় সতর্ক থাকুন, কারণ প্রতিটি রিকম্পোজিশন পাসে .equals()-এর সাথে প্রতিটি এলিমেন্ট তুলনা করা রিকম্পোজিশনের চেয়েও বেশি ব্যয়বহুল হতে পারে।
  • অন্যান্য মডিউল: Compose সেইসব মডিউলের ক্লাসকে অস্থির হিসেবে বিবেচনা করে যেখানে Compose কম্পাইলার রান করে না (স্ট্রং স্কিপিং মোডের অধীনে === ব্যবহার করে তুলনা করা হয়)। কোনও ডেটা সোর্স যদি একই ভ্যালু সহ নন-কম্পোজ মডিউল থেকে ছোট, ফ্ল্যাট মডেল ঘন ঘন রি-ইনস্ট্যান্টিয়েট করে, তাহলে আপনি একটি স্টেবিলিটি কনফিগারেশন ফাইল কনফিগার করতে পারেন বা @Stable অথবা @Immutable ব্যবহার করতে পারেন যেখানে .equals() সস্তা।

আরও পড়ুন