Compose-এ থিঙ্কিং

Jetpack Compose হল Android-এর জন্য আধুনিক ডিক্ল্যারেটিভ UI টুলকিট। Compose আপনার অ্যাপ UI লেখা ও ম্যানেজ করাকে সহজ করে তোলে। এটি ডিক্ল্যারেটিভ API প্রদান করে যা আপনাকে বাধ্যতামূলকভাবে ফ্রন্টএন্ড ভিউ পরিবর্তন না করেই অ্যাপ UI রেন্ডার করতে দেয়। এই পরিভাষাটি ব্যাখ্যা করা প্রয়োজন, তবে আপনার অ্যাপ ডিজাইনের জন্য এর প্রভাব গুরুত্বপূর্ণ।

ডিক্ল্যারেটিভ প্রোগ্রামিং প্যারাডাইম

ঐতিহাসিকভাবে, Android ভিউ হায়ারার্কিকে UI উইজেটের ট্রি হিসেবে উপস্থাপন করা হয়েছে। ব্যবহারকারীর ইন্টার‍্যাকশনের মতো কারণে অ্যাপের অবস্থা পরিবর্তিত হলে, বর্তমান ডেটা দেখানোর জন্য UI হায়ারার্কি আপডেট করতে হবে। UI আপডেট করার সবচেয়ে সাধারণ উপায় হল findViewById()-এর মতো ফাংশন ব্যবহার করে ট্রি ওয়াক করা এবং button.setText(String), container.addChild(View) বা img.setImageBitmap(Bitmap)-এর মতো মেথড কল করে নোড পরিবর্তন করা। এইসব পদ্ধতি উইজেটের ইন্টার্নাল স্টেট পরিবর্তন করে।

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

গত কয়েক বছর ধরে, সমগ্র ইন্ডাস্ট্রি একটি ডিক্ল্যারেটিভ UI মডেলে শিফট করা শুরু করেছে, যা ইউজার ইন্টারফেস তৈরি ও আপডেট করার প্রসেসকে সহজ করে তোলে।

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

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

কম্পোজেবল ফাংশনের উদাহরণ

Compose ব্যবহার করে, আপনি ডেটা গ্রহণ করে এবং UI এলিমেন্ট নির্গমন করে এমন একগুচ্ছ কম্পোজ করার উপযুক্ত ফাংশন নির্ধারণ করে আপনার ইউজার ইন্টারফেস তৈরি করতে পারেন। Greeting উইজেট হল একটি উদাহরণ যা String ইনপুট নেয় এবং Text উইজেট আউটপুট দেয় যা একটি অভিবাদন মেসেজ দেখায়।

একটি ফোনে Hello World টেক্সট এবং সেই UI জেনারেট করা কম্পোজ করার উপযুক্ত ফাংশনের কোড দেখানো হচ্ছে
  ।
ছবি ১. একটি কম্পোজ করার উপযুক্ত ফাংশন যা ডেটা পাস করে এবং এটি ব্যবহার করে স্ক্রিনে একটি টেক্সট উইজেট রেন্ডার করে।

এই ফাংশন সম্পর্কে কয়েকটি গুরুত্বপূর্ণ বিষয়:

  • অ্যানোটেশন: ফাংশনটি @Composable অ্যানোটেশন দিয়ে অ্যানোটেট করা হয়েছে। সব কম্পোজ করার উপযুক্ত ফাংশনে এই অ্যানোটেশন থাকতে হবে। এই অ্যানোটেশন Compose কম্পাইলারকে জানায় যে এই ফাংশনটি ডেটাকে UI-তে কনভার্ট করার উদ্দেশ্যে লেখা হয়েছে।
  • ডেটা ইনপুট: ফাংশনটি ডেটা নেয়। কম্পোজ করার উপযুক্ত ফাংশন প্যারামিটার গ্রহণ করতে পারে, যা অ্যাপের লজিককে UI বর্ণনা করতে দেয়। এই ক্ষেত্রে, আমাদের উইজেট একটি String গ্রহণ করে যাতে এটি ব্যবহারকারীকে নাম ধরে সম্বোধন করতে পারে।
  • UI ডিসপ্লে: ফাংশনটি UI-তে টেক্সট দেখায়। এটি Text() কম্পোজ করার উপযুক্ত ফাংশনকে কল করে এটি করে, যা আসলে টেক্সট UI এলিমেন্ট তৈরি করে। অন্যান্য কম্পোজেবল ফাংশনকে কল করে কম্পোজেবল ফাংশন UI হায়ারার্কি এমিট করে।
  • কোনও রিটার্ন ভ্যালু নেই: ফাংশনটি কোনও ভ্যালু রিটার্ন করে না। যেসব Compose ফাংশন UI এমিট করে সেগুলিকে কিছু রিটার্ন করতে হয় না, কারণ সেগুলি UI উইজেট তৈরি করার পরিবর্তে টার্গেট স্ক্রিনের স্টেট বর্ণনা করে।
  • প্রপার্টি: এই ফাংশনটি দ্রুত, আইডেমপোটেন্ট এবং সাইড-ইফেক্ট মুক্ত।

    • একই আর্গুমেন্ট দিয়ে একাধিকবার কল করা হলেও ফাংশনটি একই আচরণ করে এবং এটি গ্লোবাল ভেরিয়েবল বা random()-এর মতো অন্যান্য ভ্যালু ব্যবহার করে না।
    • ফাংশনটি কোনও পার্শ্বপ্রতিক্রিয়া ছাড়াই UI বর্ণনা করে, যেমন প্রপার্টি বা গ্লোবাল ভেরিয়েবল পরিবর্তন করা।

    সাধারণত, রিকম্পোজিশন-এ আলোচিত কারণগুলির জন্য, সমস্ত কম্পোজ করার উপযুক্ত ফাংশন এইসব প্রপার্টি সহ লিখতে হবে।

ডিক্ল্যারেটিভ প্যারাডাইম শিফট

অনেকগুলি অপরিহার্য অবজেক্ট-ওরিয়েন্টেড UI টুলকিটের সাহায্যে, আপনি উইজেটের একটি ট্রি ইনস্ট্যানশিয়েট করে UI ইনিশিয়ালাইজ করেন। আপনি প্রায়ই XML লেআউট ফাইল ইনফলেটের মাধ্যমে এটি করেন। প্রতিটি উইজেট নিজস্ব ইন্টার্নাল স্টেট বজায় রাখে এবং গেটার ও সেটার পদ্ধতি এক্সপোজ করে যা অ্যাপ লজিককে উইজেটের সাথে ইন্টার‍্যাক্ট করতে দেয়।

Compose-এর ডিক্ল্যারেটিভ অ্যাপ্রোচে, উইজেট তুলনামূলকভাবে স্টেটলেস হয় এবং সেটার বা গেটার ফাংশন এক্সপোজ করে না। আসলে, উইজেটকে অবজেক্ট হিসেবে এক্সপোজ করা হয় না। আপনি আলাদা আলাদা আর্গুমেন্ট সহ একই কম্পোজ করার উপযুক্ত ফাংশন কল করে UI আপডেট করেন। এটি অ্যাপ আর্কিটেকচার সংক্রান্ত নির্দেশিকায় বর্ণিত ViewModel-এর মতো আর্কিটেকচারাল প্যাটার্নে স্টেট প্রদান করার প্রক্রিয়াকে সহজ করে তোলে। তারপরে, আপনার কম্পোজ করার উপযুক্ত আইটেমগুলি প্রতিবার অবজার্ভ করা ডেটা আপডেট হলে, বর্তমান অ্যাপ্লিকেশন স্টেটকে UI-তে ট্রান্সফর্ম করার জন্য দায়ী।

Compose UI-তে ডেটা ফ্লোয়ের ইলাস্ট্রেশন, হাই-লেভেল অবজেক্ট থেকে শুরু করে
সেগুলির চাইল্ড পর্যন্ত।
ছবি ২. অ্যাপ লজিক, টপ-লেভেল কম্পোজ করার উপযুক্ত ফাংশনে ডেটা প্রদান করে। সেই ফাংশনটি অন্যান্য কম্পোজেবলকে কল করে UI বর্ণনা করার জন্য ডেটা ব্যবহার করে এবং সেইসব কম্পোজেবল ও হায়ারার্কির নিচের দিকে উপযুক্ত ডেটা পাস করে।

ব্যবহারকারী UI-এর সাথে ইন্টার‍্যাক্ট করলে, UI onClick-এর মতো ইভেন্ট তৈরি করে। সেইসব ইভেন্ট অ্যাপের লজিককে বিজ্ঞপ্তি পাঠাবে, যা অ্যাপের স্টেট পরিবর্তন করতে পারে। স্ট্যাটাস পরিবর্তন হলে, নতুন ডেটা সহ কম্পোজ করার উপযুক্ত ফাংশন আবার কল করা হয়। এর ফলে UI এলিমেন্ট আবার আঁকতে হয়--এই প্রসেসকে রিকম্পোজিশন বলা হয়।

UI এলিমেন্ট কীভাবে ইন্টার‍্যাকশনের উত্তর দেয় তার ইলাস্ট্রেশন, এর জন্য অ্যাপ
লজিক দ্বারা ম্যানেজ করা ইভেন্ট ট্রিগার করা হয়।
ছবি ৩. ব্যবহারকারী একটি UI এলিমেন্টের সাথে ইন্টার‍্যাক্ট করেছেন, যার ফলে একটি ইভেন্ট ট্রিগার হয়েছে। অ্যাপ লজিক ইভেন্টের উত্তর দেয়, তারপর প্রয়োজন হলে কম্পোজ করার উপযুক্ত ফাংশন নতুন প্যারামিটার সহ অটোমেটিক আবার কল করা হয়।

ডায়নামিক কন্টেন্ট

যেহেতু কম্পোজ করার উপযুক্ত ফাংশন XML-এর পরিবর্তে Kotlin-এ লেখা হয়, তাই সেগুলি অন্য যেকোনও Kotlin কোডের মতো ডায়নামিক হতে পারে। যেমন, ধরুন আপনি এমন একটি UI তৈরি করতে চান যা ব্যবহারকারীদের একটি তালিকা স্বাগত জানায়:

@Composable
fun Greeting(names: List<String>) {
    for (name in names) {
        Text("Hello $name")
    }
}

এই ফাংশনটি নামের একটি তালিকা নেয় এবং প্রতিটি ব্যবহারকারীর জন্য একটি করে অভিবাদন তৈরি করে। কম্পোজেবল ফাংশন বেশ জটিল হতে পারে। আপনি কোনও নির্দিষ্ট UI এলিমেন্ট দেখাতে চান কিনা তা স্থির করতে if স্টেটমেন্ট ব্যবহার করতে পারেন। আপনি লুপ ব্যবহার করতে পারবেন। আপনি সহায়ক ফাংশন কল করতে পারবেন। আপনি মূল ভাষার সম্পূর্ণ সুবিধা পাবেন। এই ক্ষমতা ও নমনীয়তা Jetpack Compose-এর অন্যতম প্রধান সুবিধা।

রিকম্পোজিশন

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

যেমন, এই কম্পোজেবল ফাংশনের কথা বিবেচনা করুন যা একটি বোতাম দেখায়:

@Composable
fun ClickCounter(clicks: Int, onClick: () -> Unit) {
    Button(onClick = onClick) {
        Text("I've been clicked $clicks times")
    }
}

যতবার বোতামে ক্লিক করা হয়, কলার clicks-এর ভ্যালু আপডেট করে। নতুন ভ্যালু দেখানোর জন্য Compose Text ফাংশনের সাথে আবার lambda কল করে; এই প্রসেসকে রিকম্পোজিশন বলা হয়। অন্যান্য ফাংশন যা ভ্যালুর উপর নির্ভর করে না, সেগুলি আবার কম্পোজ করা হয় না।

আমরা আগেই আলোচনা করেছি যে, সম্পূর্ণ UI ট্রি আবার কম্পোজ করা হলে তা কম্পিউটেশনালি খরচসাপেক্ষ হতে পারে, এর ফলে কম্পিউটিং পাওয়ার ও ব্যাটারির আয়ু কমে যায়। Compose এই স্মার্ট রিকম্পোজিশন-এর মাধ্যমে এই সমস্যার সমাধান করে।

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

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

  • শেয়ার করা অবজেক্টের প্রপার্টিতে লেখা
  • ViewModel-এ কোনও অবজার্ভেবল আপডেট করা
  • শেয়ার করা পছন্দ আপডেট করা

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

যেমন, এই কোডটি SharedPreferences-এ একটি ভ্যালু আপডেট করার জন্য একটি কম্পোজ করার উপযুক্ত ফাংশন তৈরি করে। কম্পোজ করার উপযুক্ত আইটেমটি শেয়ার করা প্রেফারেন্স থেকে পড়তে বা লিখতে পারবে না। পরিবর্তে, এই কোডটি ViewModel ব্যাকগ্রাউন্ড করুটিনে রিড ও রাইটকে সরিয়ে দেয়। আপডেট ট্রিগার করার জন্য অ্যাপ লজিক কলব্যাকের সাথে বর্তমান ভ্যালু পাস করে।

@Composable
fun SharedPrefsToggle(
    text: String,
    value: Boolean,
    onValueChanged: (Boolean) -> Unit
) {
    Row {
        Text(text)
        Checkbox(checked = value, onCheckedChange = onValueChanged)
    }
}

আপনি 'কম্পোজ' ফিচার ব্যবহার করার সময় যেসব বিষয় সম্পর্কে সচেতন থাকতে হবে, এই ডকুমেন্টে সেগুলি নিয়ে আলোচনা করা হয়েছে:

  • রিকম্পোজিশন যত বেশি সম্ভব কম্পোজ করার উপযুক্ত ফাংশন ও ল্যাম্বডা এড়িয়ে যায়।
  • রিকম্পোজিশন অপ্টিমাইজ করা হয় এবং বাতিল করা হতে পারে।
  • কোনও কম্পোজ করার উপযুক্ত ফাংশন খুব ঘন ঘন রান করতে পারে, এমনকি কোনও অ্যানিমেশনের প্রতিটি ফ্রেমের মতো ঘন ঘনও রান করতে পারে।
  • কম্পোজেবল ফাংশন প্যারালালভাবে এক্সিকিউট করতে পারে।
  • কম্পোজেবল ফাংশন যেকোনও ক্রমে এক্সিকিউট করা যেতে পারে।

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

রীকম্পোজিশন যতটা সম্ভব এড়িয়ে যায়

আপনার UI-এর কিছু অংশ ভুল হলে, Compose শুধুমাত্র সেই অংশগুলি আবার কম্পোজ করার জন্য যথাসাধ্য চেষ্টা করে যেগুলি আপডেট করতে হবে। এর অর্থ হল, এটি UI ট্রি-তে কোনও কম্পোজ করার মতো আইটেম বেশি বা কম না করে, একটি Button'র কম্পোজ করার মতো আইটেম আবার চালানোর জন্য স্কিপ করতে পারে।

প্রতিটি কম্পোজ করার উপযুক্ত ফাংশন ও ল্যামডা নিজে থেকেই আবার কম্পোজ হতে পারে। নিচে দেওয়া উদাহরণে দেখানো হয়েছে যে কীভাবে কোনও তালিকা রেন্ডার করার সময় রিকম্পোজিশন কিছু এলিমেন্ট এড়িয়ে যেতে পারে:

/**
 * Display a list of names the user can click with a header
 */
@Composable
fun NamePicker(
    header: String,
    names: List<String>,
    onNameClicked: (String) -> Unit
) {
    Column {
        // this will recompose when [header] changes, but not when [names] changes
        Text(header, style = MaterialTheme.typography.bodyLarge)
        HorizontalDivider()

        // LazyColumn is the Compose version of a RecyclerView.
        // The lambda passed to items() is similar to a RecyclerView.ViewHolder.
        LazyColumn {
            items(names) { name ->
                // When an item's [name] updates, the adapter for that item
                // will recompose. This will not recompose when [header] changes
                NamePickerItem(name, onNameClicked)
            }
        }
    }
}

/**
 * Display a single name the user can click.
 */
@Composable
private fun NamePickerItem(name: String, onClicked: (String) -> Unit) {
    Text(name, Modifier.clickable(onClick = { onClicked(name) }))
}

রিকম্পোজিশনের সময় এই স্কোপগুলির মধ্যে যেকোনও একটিই শুধু এক্সিকিউট করা হতে পারে। header পরিবর্তন হলে, Compose Column ল্যাম্বডায় চলে যেতে পারে, তবে এর কোনও প্যারেন্ট এক্সিকিউট করবে না । এবং Column এক্সিকিউট করার সময়, names পরিবর্তন না হলে, Compose LazyColumn-এর আইটেম এড়িয়ে যেতে পারে।

আবারও বলছি, সব কম্পোজ করা যায় এমন ফাংশন বা ল্যামডাকে সাইড-ইফেক্ট ফ্রি হতে হবে। আপনাকে কোনও সাইড-ইফেক্ট পারফর্ম করতে হলে, কলব্যাক থেকে এটি ট্রিগার করুন।

পুনর্গঠন আশাবাদী

কম্পোজ করার মতো আইটেমের প্যারামিটার পরিবর্তিত হতে পারে বলে মনে হলেই রিকম্পোজিশন শুরু হয়। রিকম্পোজিশন অপ্টিমিস্টিক,অর্থাৎ Compose আশা করে যে প্যারামিটার আবার পরিবর্তন হওয়ার আগেই রিকম্পোজিশন সম্পূর্ণ হয়ে যাবে। রীকম্পোজিশন সম্পূর্ণ হওয়ার আগে কোনও প্যারামিটার পরিবর্তিত হলে, Compose রীকম্পোজিশন বাতিল করে নতুন প্যারামিটার দিয়ে সেটি আবার শুরু করতে পারে।

রিকম্পোজিশন বাতিল করা হলে, Compose রিকম্পোজিশন থেকে UI ট্রি বাদ দেয়। UI ডিসপ্লে করার উপর নির্ভর করে এমন কোনও পার্শ্বপ্রতিক্রিয়া থাকলে, কম্পোজিশন বাতিল করা হলেও পার্শ্বপ্রতিক্রিয়া প্রয়োগ করা হবে। এর ফলে অ্যাপের অবস্থা সঙ্গতিপূর্ণ নাও থাকতে পারে।

অপ্টিমিস্টিক রিকম্পোজিশন হ্যান্ডেল করার জন্য সব কম্পোজ করা যায় এমন ফাংশন ও ল্যাম্বডা আইডেম্পোটেন্ট ও সাইড-ইফেক্ট ফ্রি কিনা তা যাচাই করুন।

কম্পোজেবল ফাংশন প্রায়ই রান করতে পারে

কিছু ক্ষেত্রে, কোনও কম্পোজ করার উপযুক্ত ফাংশন UI অ্যানিমেশনের প্রতিটি ফ্রেমের জন্য রান করতে পারে। ফাংশনটি যদি ডিভাইস স্টোরেজ থেকে রিড করার মতো কঠিন অপারেশন পারফর্ম করে, তাহলে ফাংশনটি UI জ্যাঙ্ক করতে পারে।

যেমন, আপনার উইজেট যদি ডিভাইস সেটিংস পড়ার চেষ্টা করে, তাহলে এটি সম্ভাব্যভাবে সেকেন্ডে শত শত বার সেই সেটিংস পড়তে পারে, যার ফলে আপনার অ্যাপের পারফর্ম্যান্সের উপর খারাপ প্রভাব পড়তে পারে।

কোনও কম্পোজ করার উপযুক্ত ফাংশনের ডেটা প্রয়োজন হলে, সেই ডেটার জন্য প্যারামিটার নির্ধারণ করুন। তারপরে, আপনি কম্পোজিশনের বাইরে অন্য থ্রেডে বেশি প্রসেসিং পাওয়ারের প্রয়োজন হয় এমন কাজ করতে পারেন এবং mutableStateOf বা LiveData ব্যবহার করে কম্পোজ করার উপযুক্ত ফাংশনে প্যারামিটার হিসেবে ফলাফল পাস করতে পারেন।

কম্পোজেবল ফাংশন প্যারালালভাবে রান করতে পারে

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

এই অপ্টিমাইজেশনের অর্থ হল, কম্পোজ করার উপযুক্ত ফাংশন ব্যাকগ্রাউন্ড থ্রেডের পুলে এক্সিকিউট হতে পারে। কোনও কম্পোজেবল ফাংশন যদি ViewModel-এ কোনও ফাংশনকে কল করে, Compose একই সময়ে একাধিক থ্রেড থেকে সেই ফাংশনকে কল করতে পারে।

আপনার অ্যাপ্লিকেশন সঠিকভাবে কাজ করছে কিনা তা যাচাই করতে, সব কম্পোজ করার উপযুক্ত ফাংশনের কোনও সাইড-ইফেক্ট থাকা উচিত নয়। পরিবর্তে, কলব্যাক থেকে সাইড-এফেক্ট ট্রিগার করুন, যেমন onClick যা সবসময় UI থ্রেডে এক্সিকিউট হয়।

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

এখানে একটি কম্পোজ করার উপযুক্ত আইটেমের উদাহরণ দেওয়া হল যা একটি তালিকা ও তার সংখ্যা দেখায়:

@Composable
fun ListComposable(myList: List<String>) {
    Row(horizontalArrangement = Arrangement.SpaceBetween) {
        Column {
            for (item in myList) {
                Text("Item: $item")
            }
        }
        Text("Count: ${myList.size}")
    }
}

এই কোডে কোনও সাইড-ইফেক্ট নেই এবং এটি ইনপুট তালিকাটিকে UI-তে ট্রান্সফর্ম করে। ছোট তালিকা দেখানোর জন্য এটি খুব ভাল কোড। তবে, ফাংশনটি যদি কোনও লোকাল ভেরিয়েবলে লেখে, তাহলে এই কোডটি থ্রেড-সেফ বা সঠিক হবে না:

@Composable
fun ListWithBug(myList: List<String>) {
    var items = 0

    Row(horizontalArrangement = Arrangement.SpaceBetween) {
        Column {
            for (item in myList) {
                Card {
                    Text("Item: $item")
                    items++ // Avoid! Side-effect of the column recomposing.
                }
            }
        }
        Text("Count: $items")
    }
}

এই উদাহরণে, প্রতিটি রিকম্পোজিশনের সাথে items পরিবর্তন করা হয়। সেটি হতে পারে অ্যানিমেশনের প্রতিটি ফ্রেম অথবা তালিকা আপডেট হলে। যাই হোক, UI ভুল সংখ্যা দেখাবে। এই কারণে, Compose-এ এই ধরনের রাইট কাজ করে না; এই ধরনের রাইট নিষিদ্ধ করার মাধ্যমে, আমরা কম্পোজ করার উপযুক্ত ল্যাম্বডা এক্সিকিউট করার জন্য ফ্রেমওয়ার্ককে থ্রেড পরিবর্তন করার অনুমতি দিই।

কম্পোজেবল ফাংশন যেকোনও ক্রমে এক্সিকিউট করা যেতে পারে

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

যেমন, ধরুন আপনার কাছে এই ধরনের কোড আছে যা একটি ট্যাব লেআউটে তিনটি স্ক্রিন আঁকে:

@Composable
fun ButtonRow() {
    MyFancyNavigation {
        StartScreen()
        MiddleScreen()
        EndScreen()
    }
}

StartScreen, MiddleScreen ও EndScreen-এ কল করার সময় কোনও ক্রম অনুসরণ করা নাও হতে পারে। এর অর্থ হল, আপনি, যেমন, StartScreen()-এর মাধ্যমে কিছু গ্লোবাল ভেরিয়েবল (একটি সাইড-ইফেক্ট) সেট করতে পারবেন না এবং MiddleScreen() সেই পরিবর্তনের সুবিধা নিতে পারবেন না। পরিবর্তে, সেইসব ফাংশনের প্রত্যেকটিকে স্বয়ংসম্পূর্ণ হতে হবে।

আরও জানুন

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

ভিডিও