MutableState হল Jetpack Compose এর একটি ইন্টারফেস যা একটি পরিবর্তনযোগ্য পর্যবেক্ষণযোগ্য মানের জন্য একটি কন্টেনার প্রতিনিধিত্ব করে। এটি Compose এর প্রতিক্রিয়াশীল পদ্ধতির ভিত্তি: যখনই MutableState এর মান setter এর মাধ্যমে পরিবর্তিত হয়, Compose Runtime সকল পঠনকারী উপাদানকে অবগত করে এবং পুনর্বিন্যাস শুরু করে। Google Android Developers, 2026 অনুযায়ী, একটি ডিক্লারেটিভ UI এ অবস্থার সাথে সঠিকভাবে কাজ করার জন্য MutableState বোঝা অপরিহার্য।
মূখ্য বিষয়
MutableState হল androidx.compose.runtime প্যাকেজের একটি ইন্টারফেস যা একটি বৈশিষ্ট্য ঘোষণা করে: override var value: T। getter বর্তমান মান ফেরত দেয়, setter একটি নতুন মান লিখে এবং Compose Runtime কে পরিবর্তন সম্পর্কে অবগত করে। ইন্টারফেসটি State<T> থেকে উদ্ধার করে, যেখানে value শুধু পড়ার জন্য। এই দুই-স্তরীয় আর্কিটেক্চার অ্যাক্সেস পৃথক্করণের অনুমতি দেয়: একটি উপাদান যা শুধু মান পড়তে চায় সে State<T> পায়, যখন মালিক উপাদানটি MutableState<T> পায়।
MutableState এর ডিফল্ট বাস্তবায়ন হল অন্তর্ণিহিত ক্লাস SnapshotMutableStateImpl, যা পরিবর্তন ট্রেক করার জন্য একটি snapshot প্রক্রিয়া ব্যবহার করে। যখন value এর setter কল করা হয়, বর্তমান snapshot লিখন রেকর্ড করে এবং সকল পঞ্জীকৃত ObservedScope কে অবৈধ হিসেবে চিহ্নিত করে। এই পরিধি (সাধারণত Composable ফাংশন) পরবর্তী ফ্রেমে পুনর্বিন্যস্ত হবে। Lock-free snapshot আর্কিটেক্চার জন্য সম্পূর্ণ প্রক্রিয়াটি সিঙ্ক্রোনাসলি এবং লক ছাড়া ঘটে।
State vs MutableState: State হল একটি শুধু-পড়ার ইন্টারফেস যা সার্বজনিক উপাদান API এর জন্য ব্যবহৃত হয়। যখন আপনি একটি Composable ফাংশন প্যারামিটারকে State<Int> হিসেবে ঘোষণা করেন, আপনি গারন্টি দেন যে উপাদানটি অবস্থা পড়তে পারে কিন্তু পরিবর্তন করতে পারে না। MutableState মালিক উপাদানের মধ্যে ব্যবহৃত হয়। এই পৃথক্করণ Compose এর একটি মৌলিক অভ্যাস যা অনাধিকৃত পরিবর্তন প্রতিরোধ করে।
Compose এ অবস্থা ইন্টারফেসের পদক্রমে বেশ কয়েকটি স্তর আছে। সর্বোচ্চে রয়েছে State<T> শুধু-পড়ার value সহ। নিচে রয়েছে MutableState<T> পড়া-লেখা value সহ। এরপর আসে বিশেষায়িত প্রাইমিটিভ সংস্করণ: MutableIntState, MutableFloatState, MutableLongState, MutableBooleanState এবং অন্যান্য, যা প্রাইমিটিভ বক্সিং এড়ায়।
MutableDoubleState এবং MutableLongState কম সাধারণ কিন্তু এও বিদ্যমান। সংগ্রহ ইন্টারফেস: MutableListState — একটি তালিকার মধ্যে পরিবর্তন ট্রেক করার জন্য, MutableStateMap — ম্যাপের জন্য। এগুলোর প্রত্যেকটি একটি নির্দিষ্ট পরিস্থিতির জন্য অপ্টিমাইজড এবং অতিরিক্ত সংগ্রহ পরিচালনা পদ্ধতি সহ মৌলিক MutableState বাড়িয়ে দেয়।
SnapshotStateList এবং SnapshotStateMap হল snapshot-সংগত পরিবর্তনযোগ্য তালিকা এবং ম্যাপের বাস্তবায়ন। এরা শুধু মান প্রতিস্থাপনই নয়, অন্তর্ণিহিত পরিবর্তন ট্রেক করতে পারে: একটি তালিকায় আইটেম যোগ করা, মুছে ফেলা, একটি বিদ্যমান আইটেম পরিবর্তন করা। এই গঠনগুলোর জন্য, mutableStateListOf() এবং mutableStateMapOf() সংশ্লিষ্ট পর্যবেক্ষণযোগ্য সংগ্রহ তৈরি করে।
| ইন্টারফেস | উদ্দেশ্য | তৈরির পদ্ধতি |
|---|---|---|
| State<T> | শুধু-পড়ার কন্টেনার | — |
| MutableState<T> | পড়া-লেখার কন্টেনার | mutableStateOf() |
| MutableIntState | বক্সিং ছাড়া প্রাইমিটিভ Int | mutableIntStateOf() |
| MutableFloatState | বক্সিং ছাড়া প্রাইমিটিভ Float | mutableFloatStateOf() |
| SnapshotStateList | পর্যবেক্ষণযোগ্য তালিকা | mutableStateListOf() |
| SnapshotStateMap | পর্যবেক্ষণযোগ্য ম্যাপ | mutableStateMapOf() |
SnapshotMutationPolicy হল একটি ইন্টারফেস যা নির্ধারণ করে কোন MutableState পরিবর্তনকে গুরুত্বপূর্ণ বলে বিবেচিত করা হয়। mutableStateOf দ্বিতীয় যুক্তি হিসেবে policy গ্রহণ করে। মানক বাস্তবায়ন: structuralEquality() (equals), referentialEquality() (===), neverEqualPolicy() (সবসময় পরিবর্তনকে গুরুত্বপূর্ণ বলে মনে করে)। কাস্টম যুক্তির জন্য নিজস্ব নীতি বাস্তবায়ন করা যেতে পারে।
structuralEquality() — ডিফল্ট আচরণ। Compose নতুন মানকে পুরনোটির সাথে equals() ব্যবহার করে তুলনা করে। যদি ফলাফল true হয়, পুনর্বিন্যাস শুরু হয় না। এটি প্রাইমিটিভ এবং data classes এর জন্য সুবিধাজনক, যেখানে সমান ক্ষেত্রের দুটি উদাহরণকে সমান বলে বিবেচিত করা হয়। সমস্যা: যদি data class এ একটি List থাকে, তবে equals() একটি গভীর তুলনা করে, যা বড় তালিকার জন্য ব্যয়বহুল হতে পারে।
referentialEquality() — === ব্যবহার করে রিফারেন্স তুলনা করে। পুনর্বিন্যাস শুধু তখনই শুরু হয় যখন একটি ভিন্ন অবজেক্ট নির্দিষ্ট করা হয়, যদিও বিষয়বস্তু আবন্তুর সমান হয়। এটি অপরিবর্তনীয় data classes এর জন্য সবচেয়ে উপযুক্ত যেখানে প্রতিটি নতুন উদাহরণ একটি পরিবর্তনের গারন্টি দেয়। neverEqualPolicy() — তুলনা না করে সবসময় পরিবর্তনকে গুরুত্বপূর্ণ বলে বিবেচিত করে। যখন setter কভনো কভনো ডাকা হয় এবং equals এ সময় ব্যয় করার প্রয়োজন নেই তখন দকারি।
// Policy comparison in practice
data class User(val name: String, val age: Int)
@Composable
fun UserProfile() {
// structuralEquality: recomposition ONLY if data changed
var user1 by remember {
mutableStateOf(User("Alice", 30))
}
// referentialEquality: recomposition on ANY assignment
var user2 by remember {
mutableStateOf(User("Bob", 25),
SnapshotMutationPolicy.referentialEquality())
}
// user1: copy() with same fields does NOT trigger recomposition
// user2: even user2.copy() == user2 triggers recomposition (new ref)
}
প্রাইমিটিভ MutableIntState এবং অনুরূপ হল বিশেষায়িত ইন্টারফেস যা বক্সিং ছাড়া প্রাইমিটিভ সংরক্ষণ করে। একটি সাধারণ MutableState<Int> Int কে Integer হিসেবে সংরক্ষণ করে, যা প্রতি লেখায় হিএপে একটি অবজেক্ট তৈরি করে। MutableIntState int (প্রাইমিটিভ) সংরক্ষণ করে, সম্পূর্ণরূপে বক্সিং ওভারহেড দূর করে। এটি উচ্চ-ফ্রিকোয়েন্সির আপডেটের জন্য বিশেষ গুরুত্বপূর্ণ — কাউন্টার, স্ক্রল পঞ্জিকা, অ্যানিমেশন মান।
mutableIntStateOf(), mutableFloatStateOf(), mutableLongStateOf() — ফাংশন যা প্রাইমিটিভ MutableState তৈরি করে। ইন্টারফেসগুলোকে MutableIntState, MutableFloatState, MutableLongState বলা হয়। এরা যথাক্রমে MutableState<Int>, MutableState<Float> এবং MutableState<Long> বাড়িয়ে দেয়, দ্রুত প্রাইমিটিভ অ্যাক্সেসের জন্য intValue বৈশিষ্ট্য যোগ করে। এদের অন্তর্ণিহিত বাস্তবায়নে লক-ফ্রি পড়া/লেখার জন্য AtomicInteger ব্যবহার করে।
ব্যবহার: কাউন্টার (Int), স্ক্রল পঞ্জিকা (Float offset), সময়স্থাপক (Long)। অধিকাংশ দৈনন্দিন পরিস্থিতিতে কার্যদক্ষতার পার্থক্য অধিক নয়, কিন্তু হাজার আইটেম এবং সংক্রমণ অ্যানিমেশন সহ LazyList এ, প্রাইমিটিভ State উল্লেখযোগ্য বৃদ্ধি দেয়। Google সার্বত্রিক mutableStateOf এর পরিবর্তে বিশিষ্ট পরিস্থিতির জন্য প্রাইমিটিভ State ব্যবহার করার পরামর্শ দেয়।
@Composable
fun ScrollCounter() {
// Bad: boxing on every update
var badCount by remember { mutableStateOf(0) }
// Good: no boxing, primitive storage
var goodCount by remember { mutableIntStateOf(0) }
// Usage is identical
Button(onClick = { goodCount++ }) {
Text("Count: $goodCount")
}
}
একটি TodoList উপাদান বিবেচনা করুন, যেখানে MutableState দুটি রূপে ব্যবহৃত হয়: ইনপুট অবস্থার জন্য পৃথক ভেরিয়েবল এবং একটি গতিশীল কাজের তালিকার জন্য SnapshotStateList হিসেবে। উভয়েই কোড সংক্ষিপ্ততার জন্য ডিলিগেশন ব্যবহার করে।
data class TodoItem(val id: Int, val text: String, val isDone: Boolean = false)
@Composable
fun TodoScreen() {
var inputText by remember { mutableStateOf("") }
val items = remember { mutableStateListOf() }
Column(modifier = Modifier.padding(16.dp)) {
Row {
TextField(
value = inputText,
onValueChange = { inputText = it }
)
Button(onClick = {
if (inputText.isNotBlank()) {
items.add(TodoItem(items.size, inputText))
inputText = ""
}
}) { Text("Add") }
}
LazyColumn {
items(items) { item ->
Row(modifier = Modifier.fillMaxWidth().clickable {
val idx = items.indexOf(item)
items[idx] = item.copy(isDone = !item.isDone)
}) {
Checkbox(checked = item.isDone, onCheckedChange = null)
Text(item.text)
}
}
}
}
}
mutableStateListOf একটি SnapshotStateList তৈরি করে — একটি পরিবর্তনযোগ্য তালিকা যা পরিবর্তন ট্রেক করে। যখন items.add() এবং items[n] = newValue ডাকা হয়, Compose মিউটেশন দেখে এবং শুধু LazyColumn এর সেই উপাদানগুলোকে পুনর্বিন্যস্ত করে যা পরিবর্তিত হয়েছে। inputText হল একটি সাধারণ MutableState<String>। দুই MutableState ধরনের (একক এবং সংগ্রহ) সম্মিলন ফর্ম এবং তালিকা সহ পর্দার জন্য একটি নির্দিষ্ট প্যাটার্ন।
সাধারণ প্রশ্নোত্তরি
MutableState remember ছাড়া প্রতি পুনর্বিন্যাসে নতুন করে তৈরি হবে। mutableStateOf এর প্রতিটি নতুন কল একটি নতুন অবজেক্ট তৈরি করে, এবং পুরনো মান হারিয়ে যায়। সবসময় State সংরক্ষণের জন্য remember ব্যবহার করুন, যত ক্ষণ না State Composable এর বাইরে তৈরি হয় (যেমন ViewModel এ)।
.value snapshot { } এর মাধ্যমে snapshot এর বাইরে একবার পড়ুন। কিন্তু এটি প্রতিক্রিয়াশীলতা নিষ্ক্রিয় করে — পরিবর্তনগুলো আর পুনর্বিন্যাস শুরু করবে না। সাবস্ক্রিপশন ছাড়া একবার পড়ার জন্য, পড়া ছাড়া snapshot এর মধ্যে currentValue() ব্যবহার করুন।
mutableIntStateOf দ্রুততর কারণ এটির int কে Integer এ বুক্স করার প্রয়োজন নেই। প্রতি সেকেন্ডে হাজার আপডেট (অ্যানিমেশন, স্ক্রলিং) এ, পার্থক্য আবন্টন সময়ে 30-50% পর্যন্ত পৌঁছতে পারে। বিরল আপডেটের জন্য (ক্লিক, টেক্সট ইনপুট), পার্থক্য নাগণ্য।
হ্যাঁ, কিন্তু সুপারিশ করা হয় না। MutableState এর পরিবর্তে, State (শুধু-পড়ার) + onValueChange ল্যাম্বডা পাস করুন। এটি State Hoisting প্যাটার্ন বাস্তবায়ন করে এবং উপাদানটিকে পুনর্ব্যবহারযোগ্য করে। MutableState গ্রহণ করা উপাদানগুলো একদিকীয় ডেটা প্রবাহ লঙ্ঘন করে।
MutableState ইন্টারফেস বাস্তবায়ন করুন এবং getter এবং setter সহ override var value প্রদান করুন। setter এ আপনি বৈধতা বা লগিং যোগ করতে পারেন। Compose Runtime এর সাথে পিছু সংগততার জন্য, আপনার কাস্টম বাস্তবায়নকে snapshotFlow এ মোড়ান বা snapshotIncrement ব্যবহার করুন।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন