Recomposition হল Jetpack Compose-এর একটি মেকানিজম যা ডেটা পরিবর্তনের সময় ব্যবহারকারী ইন্টারফেসের অংশগুলি স্বয়ংক্রিয়ভাবে পুনর্নির্মাণ করে, ম্যানুয়াল View আপডেট ছাড়া। যখন একটি অবস্থা ভেরিয়েবল যার উপর Composable ফাংশন নির্ভর করে তার মান পরিবর্তন করে, Compose শুধুমাত্র সেই ফাংশনটি পুনরায় চালু করে, বাকি UI ট্রি অপরিবর্তিত রেখে। Google Android Developers, 2026-এর মতে, Recomposition-এর সঠিক বোঝাপড়া অপ্রয়োজনীয় পুনরায় অঙ্কন 40–60% কমাতে দেয়।
মূল পয়েন্ট
Recomposition হল Composable ফাংশনের পুনরায় নির্বাহ যা ইতিমধ্যে Composition-এ অংশ নিয়েছে, নতুন প্যারামিটার বা অবস্থার মান সহ। পুনঃসংযোজনের মূল লক্ষ্য হল শুরু থেকে সম্পূর্ণ ইন্টারফেস পুনর্নির্মাণ না করে UI ট্রিকে বর্তমান ডেটার সাথে সিঙ্ক্রোনাইজ করা। Composition-এর বিপরীতে, যা একবার ঘটে, Recomposition স্ক্রিনের জীবনকালে শতবার ট্রিগার হতে পারে।
Recomposition স্মার্ট ইনভ্যালিডেশন নীতিতে কাজ করে: Compose ট্র্যাক করে প্রতিটি Composable ফাংশন কোন State অবজেক্ট পড়ে এবং শুধুমাত্র সেগুলিকে পুনরায় চালু করার জন্য চিহ্নিত করে যাদের নির্ভরতা পরিবর্তিত হয়েছে। এটি স্ন্যাপশট সিস্টেমের মাধ্যমে অর্জিত হয়, যা নির্বাহের সময় সমস্ত State পড়ার অপারেশন রেকর্ড করে, এবং Composer, যা এই নির্ভরতাগুলিকে নির্দিষ্ট ফাংশনে ম্যাপ করে।
বোঝা গুরুত্বপূর্ণ: পুনঃসংযোজন মানে তাৎক্ষণিক স্ক্রিন পুনরায় অঙ্কন নয়। Compose তিনটি ধাপে কাজ করে: Composition (UI বর্ণনা তৈরি), Layout (আকার এবং অবস্থান গণনা), এবং Drawing (ক্যানভাসে রেন্ডারিং)। যদি পুনঃসংযোজনের পরে উপাদানগুলির আকার এবং অবস্থান না বদলায়, Layout ধাপ এড়ানো যেতে পারে। যদি চাক্ষুষ চেহারা না বদলায় — Drawing এড়িয়ে যাওয়া হয়। এই তিন-ধাপের আর্কিটেকচার প্রতিটি UI আপডেটের ন্যূনতম খরচ নিশ্চিত করে।
পুনঃসংযোজন-এর তিনটি প্রধান ট্রিগার রয়েছে। প্রথম — Composable ফাংশনের বডিতে পড়া State অবজেক্টের পরিবর্তন। যখন mutableStateOf বা derivedStateOf তার মান পরিবর্তন করে, পূর্ববর্তী composition-এ এই State পড়া সমস্ত ফাংশন পুনরায় চালু করার জন্য চিহ্নিত হয়।
দ্বিতীয় ট্রিগার — প্যারেন্ট ফাংশন থেকে কল করার সময় Composable ফাংশনের প্যারামিটার পরিবর্তন। যদি প্যারেন্ট ফাংশন একটি নতুন মান পাঠায় (উদাহরণস্বরূপ, টেক্সট বা সংখ্যা পরিবর্তিত হয়েছে), চাইল্ড ফাংশন পুনরায় চালু হবে, এমনকি যদি এটি অভ্যন্তরীণভাবে State না পড়ে। Compose equals-এর মাধ্যমে নতুন এবং পুরানো প্যারামিটার মান তুলনা করে, এবং যদি তারা সমান হয় — ফাংশন এড়িয়ে যাওয়া যেতে পারে।
তৃতীয় ট্রিগার — CompositionLocalProvider-এর মাধ্যমে CompositionLocal পরিবর্তন। .current-এর মাধ্যমে CompositionLocal পড়া সমস্ত ফাংশন প্রদানকারী পরিবর্তনে পুনরায় চালু হয়। এই মেকানিজম MaterialTheme ব্যবহার করে: থিম পরিবর্তন (হালকা/গাঢ়) MaterialTheme.colorScheme পড়া সমস্ত উপাদানের পুনঃসংযোজন ঘটায়।
@Composable
fun RecompositionDemo() {
var counter by remember { mutableStateOf(0) }
var text by remember { mutableStateOf("Hello") }
Column {
Text("Counter: $counter") // recomposition when counter changes
Text("Message: $text") // recomposition when text changes
Button(onClick = { counter++ }) {
Text("+1")
}
Button(onClick = { text = "World" }) {
Text("Change Text")
}
}
}
+1 বাটনে ক্লিক করলে counter পরিবর্তিত হয়, যা শুধুমাত্র প্রথম Text লাইন এবং Column-এর পুনঃসংযোজন ঘটায়। text প্রদর্শনকারী দ্বিতীয় Text লাইন পুনরায় চালু হয় না। এই বিচ্ছিন্নতা স্ন্যাপশট সিস্টেমের ফলাফল: প্রতিটি Composable ফাংশন শুধুমাত্র সেই State অবজেক্ট সম্পর্কে জানে যা এটি পড়েছে।
পুনঃসংযোজন-এর অপ্টিমাইজেশন সঠিক ডেটা স্ট্রাকচার নির্বাচনের মাধ্যমে শুরু হয়। পরিবর্তনযোগ্য (mutableListOf)-এর পরিবর্তে অপরিবর্তনীয় সংগ্রহ (listOf, mapOf) ব্যবহার করুন। Compose equals-এর মাধ্যমে প্যারামিটার তুলনা করে, এবং যদি একটি সংগ্রহ পরিবর্তিত হয় কিন্তু equals true ফেরত দেয় — ফাংশন পুনরায় চালু হবে না। পরিবর্তনযোগ্য সংগ্রহের জন্য, SnapshotStateList ব্যবহার করুন, যা উপাদান স্তরে সঠিক পরিবর্তন ট্র্যাকিং প্রয়োগ করে।
দ্বিতীয় কৌশল — UI-এর স্থিতিশীল অংশগুলি আলাদা Composable ফাংশনে বের করে আনা। যদি স্ক্রিনের একটি অংশ ঘন ঘন পরিবর্তনশীল অবস্থার উপর নির্ভর না করে, তবে এটিকে প্যারামিটার সহ একটি আলাদা ফাংশনে বের করে নিন। যখন পুনঃসংযোজন ঘটে, স্থিতিশীল ফাংশন একই প্যারামিটার পায়, Compose সেগুলির তুলনা করে এবং নির্বাহ এড়িয়ে যায়। এটি একটি বড় ফাংশনের অংশ হিসাবে সেই অংশটি পুনরায় চালু করার চেয়ে বেশি কার্যকর যেখানে কিছু প্যারামিটার পরিবর্তিত হয়েছে।
তৃতীয় কৌশল — LazyColumn-এ কী। LazyColumn, LazyGrid এবং অন্যান্য অলস কন্টেইনারে item-এর জন্য সর্বদা key নির্দিষ্ট করুন। কী Compose-কে তালিকা পরিবর্তনে উপাদান সনাক্ত করতে দেয়: যোগ, অপসারণ বা পুনর্বিন্যাস। কী ছাড়া, Compose যেকোনো পরিবর্তনে তালিকার সমস্ত উপাদান পুনরায় চালু করে, যা বড় তালিকায় লক্ষণীয় কর্মক্ষমতা হ্রাস ঘটায়।
// Optimized structure: stable parts extracted separately
@Composable
fun OptimizedScreen(items: List<Item>) {
Column {
Header() // does not depend on items — no recomposition
Spacer(modifier = Modifier.height(8.dp))
LazyColumn {
items(items, key = { it.id }) { item ->
ItemRow(item = item) // recomposition only for changed items
}
}
}
}
@Composable
fun Header() {
Text("Item list", style = MaterialTheme.typography.headlineMedium)
}
@Composable
fun ItemRow(item: Item) {
Text(item.title)
}
Skipping হল একটি মেকানিজম যেখানে Compose একটি Composable ফাংশনের নির্বাহ এড়িয়ে যায় যদি তার সমস্ত প্যারামিটার না বদলায়। Skipping সঠিকভাবে কাজ করার জন্য, প্যারামিটার টাইপগুলি স্থিতিশীল (stable) হতে হবে। Kotlin কম্পাইলার নিম্নলিখিতগুলিকে স্থিতিশীল হিসাবে চিহ্নিত করে: আদিম টাইপ (Int, Float, Boolean), String, ল্যাম্বডা ফাংশন, এবং যেসব ক্লাসের সকল ফিল্ড স্থিতিশীল এবং val।
Stability হল @Stable বা @Immutable অ্যানোটেশন যা কাস্টম ডেটা ক্লাসে যোগ করা যেতে পারে। যদি একটি ক্লাসে পরিবর্তনযোগ্য ফিল্ড (var) থাকে, কম্পাইলার এটিকে অস্থিতিশীল মনে করে, এবং Compose এই ধরনের প্যারামিটারযুক্ত ফাংশন এড়িয়ে যেতে পারবে না। var-যুক্ত ক্লাসের জন্য, @Stable ব্যবহার করুন যদি আপনি গ্যারান্টি দেন যে পরিবর্তন বিজ্ঞপ্তি স্ন্যাপশট সিস্টেমের মাধ্যমে পাঠানো হবে।
আপনি কম্পাইলার ফ্ল্যাগ -P "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=. /reports"-এর মাধ্যমে stability পরীক্ষা করতে পারেন। এটি সমস্ত Composable ফাংশন এবং তাদের প্যারামিটারের তালিকা সহ stability নির্দেশ করে একটি রিপোর্ট তৈরি করে। যদি একটি প্যারামিটার অস্থিতিশীল হয় — সেই ফাংশনের জন্য skipping অসম্ভব, এবং এটি প্রতিটি প্যারেন্ট পুনঃসংযোজনে পুনরায় চালু হবে।
| টাইপ | স্থিতিশীলতা | Skipping |
|---|---|---|
| Int, Float, Boolean | স্থিতিশীল | হ্যাঁ |
| String | স্থিতিশীল | হ্যাঁ |
| ল্যাম্বডা | স্থিতিশীল | হ্যাঁ |
| val ফিল্ডযুক্ত data class | স্থিতিশীল | হ্যাঁ |
| var ফিল্ডযুক্ত data class | অস্থিতিশীল | না |
| List<String> | অস্থিতিশীল | না |
নোট: List<String> অস্থিতিশীল বলে গণ্য হয় কারণ এটি একটি ইন্টারফেস, কংক্রিট বাস্তবায়ন নয়। Kotlin Collections Immutable লাইব্রেরি থেকে immutableListOf() ব্যবহার করুন বা তালিকাটিকে @Stable ক্লাসে মোড়ান। ল্যাম্বডা সর্বদা স্থিতিশীল কারণ এর equals কেবল রেফারেন্স তুলনা করে, এবং কল সাইটে নতুন ল্যাম্বডা তৈরি হলে প্যারেন্ট ফাংশনও পুনরায় চালু হয়।
পুনঃসংযোজন পর্যবেক্ষণের জন্য, Android Studio Compose Recomposition Counts মোড সহ Layout Inspector প্রদান করে। এই মোডে, প্রতিটি Composable ফাংশন পুনঃসংযোজনের সংখ্যা এবং পুনরায় চালুর কারণ প্রদর্শন করে। এটি আপনাকে দ্রুত সেই ফাংশনগুলি খুঁজে পেতে দেয় যা খুব ঘন ঘন পুনঃসংযোজিত হয় এবং মূল কারণ নির্ধারণ করতে — অস্থিতিশীল প্যারামিটার বা অপ্রয়োজনীয় State নির্ভরতা।
অতিরিক্ত টুল: Compose Metrics (ইনস্ট্রুমেন্টেশন পরীক্ষার মাধ্যমে পরিসংখ্যান সংগ্রহ) এবং Recomposition Timer (প্রত্যেক ফাংশনের নির্বাহ সময় মাপা)। Google প্রোফাইলিং পর্যায়ে এই টুলগুলি সক্ষম এবং রিলিজ বিল্ডে নিষ্ক্রিয় করার সুপারিশ করে, কারণ এগুলি প্রতি পুনঃসংযোজনে 20% পর্যন্ত ওভারহেড যোগ করে।
পুনঃসংযোজন বিশ্লেষণ করার সময়, অপ্রয়োজনীয় পুনঃসংযোজন প্যাটার্ন দেখুন: একটি ফাংশন পুনরায় চালু হয় যদিও তার আউটপুট UI বদলানো উচিত নয়। একটি সাধারণ কারণ remember ছাড়া ল্যাম্বডা ব্যবহার, যেখানে প্রতিবার একটি নতুন ল্যাম্বডা অবজেক্ট তৈরি হয় এবং Compose প্যারামিটার পরিবর্তিত বলে মনে করে। সমাধান: নির্দিষ্ট ক্যাপচার সহ remember { }-এ ল্যাম্বডা মোড়ানো।
// Bad: new lambda on every parent recomposition
@Composable
fun Parent() {
Child(onClick = { doSomething() }) // new lambda every time
}
// Good: remember stabilizes the lambda
@Composable
fun Parent() {
val onClick = remember { { doSomething() } }
Child(onClick = onClick) // same reference
}
প্রায়শই জিজ্ঞাসিত প্রশ্ন
না, পুনঃসংযোজন শুধুমাত্র Composition ধাপ। এর পরে Layout এবং Drawing নির্বাহিত হয়। যদি পুনঃসংযোজনের পরে উপাদানগুলির আকার এবং অবস্থান না বদলায়, Layout এবং Drawing সম্পূর্ণভাবে এড়িয়ে যাওয়া যেতে পারে, GPU সংস্থান সাশ্রয় করে।
অ্যানিমেশনের সময়, পুনঃসংযোজন প্রতি সেকেন্ডে 120 বার পর্যন্ত চলতে পারে (120fps)। সাধারণ ইন্টারঅ্যাকশনের জন্য — প্রতি সেকেন্ডে 10–60 বার। এটি গুরুত্বপূর্ণ যে প্রতিটি পুনঃসংযোজন ফ্রেম বাজেটে (8–16 ms) ফিট করে, অন্যথায় অ্যাপ্লিকেশন ল্যাগ করবে।
কারণ প্যারেন্ট ফাংশন থেকে প্যারামিটার পরিবর্তন। প্যারেন্ট তার নিজস্ব কারণে পুনরায় চালু হয় এবং একটি নতুন মান পাঠায়। এটি এড়াতে, প্যারামিটার স্থিতিশীলতা পরীক্ষা করুন এবং ল্যাম্বডা ও গণনা করা মান স্থিতিশীল করতে remember ব্যবহার করুন।
সরাসরি নিষ্ক্রিয়করণ নেই, কিন্তু readInComposition-এর মাধ্যমে forced skipping রয়েছে — State ফাংশন বডির বাইরে পড়া হয়, যা নির্ভরতা নিবন্ধন করে না। সাবধানে ব্যবহার করুন: ফাংশন পরিবর্তনে সাড়া দেবে না, যা পুরানো UI-র কারণ হতে পারে।
Composition বেশি ব্যয়বহুল কারণ এটি শুরু থেকে সমস্ত স্লট এবং ট্রি নোড তৈরি করে। Recomposition বিদ্যমান স্লট পুনরায় ব্যবহার করে এবং শুধুমাত্র তাদের মান আপডেট করে। বাস্তবে, একটি স্ক্রিনের Composition 2–10 ms নেয়, যখন একটি একক উপাদানের পুনঃসংযোজন 0.1–1 ms নেয়।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন