mutableStateOf হল Jetpack Compose-এর একটি ফাংশন যা পরিবর্তনযোগ্য পর্যবেক্ষণযোগ্য অবস্থার একটি কন্টেইনার তৈরি করে। যখন এই কন্টেইনারের ভিতরের মান পরিবর্তিত হয়, Compose স্বয়ংক্রিয়ভাবে এই অবস্থা পড়া সমস্ত কম্পোনেন্টের পুনর্গঠন শুরু করে। mutableStateOf ছাড়া, ডেটা পরিবর্তনের সময় UI প্রতিক্রিয়াশীলভাবে আপডেট হতে পারত না। Google Android Developers, 2026 অনুযায়ী, mutableStateOf হল Compose-এ স্থানীয় অবস্থার জন্য প্রধান বিল্ডিং ব্লক।
মূল পয়েন্ট
mutableStateOf হল compose.runtime প্যাকেজের একটি ফাংশন যা একটি MutableState<T> অবজেক্ট তৈরি করে যা একটি মান সংরক্ষণ করে এবং Compose Runtime-কে পরিবর্তন সম্পর্কে জানাতে পারে। সিগনেচার: fun <T> mutableStateOf(value: T, policy: SnapshotMutationPolicy<T> = structuralEquality()): MutableState<T>. প্যারামিটার policy নির্ধারণ করে কখন একটি পরিবর্তন গুরুত্বপূর্ণ বলে বিবেচিত হবে — কাঠামোগত সমতায়, রেফারেন্সিয়াল সমতায়, বা কখনই নয়।
MutableState হল একটি ইন্টারফেস যার একটি মাত্র বৈশিষ্ট্য value: পড়ার জন্য গেটার এবং লেখার জন্য সেটার। যখন সেটার কল করা হয়, Compose Runtime একটি snapshot-এ পরিবর্তন রেকর্ড করে এবং এই State ভেরিয়েবল পড়া সমস্ত Composable ফাংশনকে পুনর্গঠনের প্রয়োজন হিসেবে চিহ্নিত করে। এই প্রক্রিয়াটি একটি একক snapshot চক্রের মধ্যে সিঙ্ক্রোনাসভাবে ঘটে, যা ক্যাসকেডিং পরিবর্তনের সময় মধ্যবর্তী অবস্থাগুলি বাদ দেয়।
প্যারামিটার policy — mutableStateOf-এর দ্বিতীয় আর্গুমেন্ট, তুলনার আচরণ নির্ধারণ করে। structuralEquality() equals() চেক করে — এটি ডিফল্ট আচরণ। referentialEquality() === (রেফারেন্সিয়াল সমতা) চেক করে। neverEqual() প্রতিটি অ্যাসাইনমেন্টকে পরিবর্তন হিসেবে বিবেচনা করে। policy-এর পছন্দ প্রভাবিত করে যে একই মান অ্যাসাইন করলে পুনর্গঠন শুরু হবে কিনা।
পর্যবেক্ষণযোগ্য অবস্থা ঘোষণার সবচেয়ে সহজ উপায় হল mutableStateOf remember-এর সাথে ব্যবহার করা। remember ছাড়া, প্রতিটি পুনর্গঠনে একটি নতুন State তৈরি হতো এবং সমস্ত আগের পরিবর্তন হারিয়ে যেত। remember নিশ্চিত করে যে Composable ফাংশন কম্পোজিশনে থাকাকালীন একই MutableState পুনর্গঠনের একটি সিরিজে টিকে থাকে।
@Composable
fun Counter() {
// প্রতিনিধিত্ব ছাড়া: .value-এর মাধ্যমে পড়া/লেখা
val count = remember { mutableStateOf(0) }
Button(onClick = { count.value++ }) {
Text("Count: ${count.value}")
}
}
@Composable
fun CounterDelegated() {
// প্রতিনিধিত্ব সহ: var + by = Property Delegation
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("Count: $count")
}
}
দুটি পদ্ধতির মধ্যে পার্থক্য হল সিনট্যাক্টিক। Property Delegation (by) একটি Kotlin কনভেনশন ব্যবহার করে: কম্পাইলার পড়া এবং লেখার জন্য getValue() এবং setValue() কল তৈরি করে। এটি count.value-এ সরাসরি অ্যাক্সেসের সমতুল্য কিন্তু একটি সাধারণ ভেরিয়েবলের সাথে কাজ করার মতো দেখায়। উভয় পদ্ধতিই কার্যকরীভাবে অভিন্ন: Compose নোটেশন নির্বিশেষে গেটারে পড়া এবং সেটারে লেখা ট্র্যাক করে।
| ফর্ম | কোড | পড়া | লেখা |
|---|---|---|---|
| প্রতিনিধিত্ব ছাড়া | val count = mutableStateOf(0) | count.value | count.value = n |
| প্রতিনিধিত্ব সহ | var count by mutableStateOf(0) | count | count = n |
Kotlin-এর প্রতিনিধিত্বকৃত বৈশিষ্ট্য পদ্ধতি Compose-এর বৈশিষ্ট্য নয় বরং ভাষার একটি অন্তর্নির্মিত ক্ষমতা। যেকোনো ক্লাস getValue(thisRef, property) এবং setValue(thisRef, property, value) অপারেটর বাস্তবায়ন করতে পারে, যার পরে এর উদাহরণ by কীওয়ার্ডের সাথে ব্যবহার করা যেতে পারে। MutableState ঠিক এইভাবেই কাজ করে: getValue বর্তমান মান ফেরত দেয় এবং setValue একটি নতুন মান অ্যাসাইন করে।
একটি গুরুত্বপূর্ণ পার্থক্য: val বনাম var। mutableStateOf val এবং var উভয়কেই অ্যাসাইন করা যেতে পারে। val (val count = mutableStateOf(0))-এর সাথে, MutableState অবজেক্ট নিজেই অপরিবর্তনীয়, কিন্তু এর value বৈশিষ্ট্য পরিবর্তন করা যেতে পারে। var (var count by mutableStateOf(0))-এর সাথে, প্রতিনিধিত্ব একটি প্রিমিটিভের সাথে কাজ করার বিভ্রম তৈরি করে, কিন্তু সেটার আসলে MutableState-এ setValue কল করে। val এবং var-এর মধ্যে নির্বাচন হল .value-এ স্পষ্ট এবং অন্তর্নিহিত অ্যাক্সেসের মধ্যে নির্বাচন।
State প্রতিনিধিত্ব হল সিনট্যাক্টিক সুগার যা কোড সহজ করে কিন্তু মেকানিক্স পরিবর্তন করে না। Kotlin কম্পাইলার var x by mutableStateOf(0) কে getter/setter-এ রূপান্তর করে যা mutableStateOf.getValue() এবং mutableStateOf.setValue() কল করে। উৎপন্ন বাইটকোডে, by-এর সাথে val এবং var-এর মধ্যে কোনো পার্থক্য নেই — উভয়ই একই MutableState কন্টেইনারের মাধ্যমে কাজ করে।
// Compose State-এর জন্য কাস্টম প্রতিনিধি
class ValidatedState<T>(initialValue: T) {
private val state = mutableStateOf(initialValue)
operator fun getValue(thisRef: Any?, property: KProperty<*>) = state.value
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
if (value != state.value) {
state.value = value
}
}
}
@Composable
fun Test() {
var text by remember { ValidatedState("") }
}
Snapshot হল Compose Runtime-এর একটি পদ্ধতি যা সমান্তরাল পরিবর্তনের সময় State পড়ার সামঞ্জস্য নিশ্চিত করে। যখন একটি Composable ফাংশন mutableStateOf পড়ে, snapshot বর্তমান মান রেকর্ড করে। যদি কম্পোজিশনের সময় অন্য একটি পরিবর্তন একই State-এ লেখে, snapshot লেখাটি দেখে কিন্তু অসামঞ্জস্যপূর্ণ ডেটা পড়তে দেয় না — পড়া সর্বদা snapshot শুরুর সময় বৈধ মান ফেরত দেয়।
যখন সেটার mutableStateOf.value = newValue কল করা হয়, Compose Runtime অবিলম্বে পুনর্গঠন শুরু করে না। পরিবর্তে, পরিবর্তনটি বর্তমান snapshot-এ নিবন্ধিত হয়। যখন snapshot প্রয়োগ করা হয় (ফ্রেম সীমানায়), Compose পরিবর্তিত State-গুলির তালিকার মাধ্যমে যায় এবং পড়া কম্পোনেন্টগুলিকে Invalid হিসাবে চিহ্নিত করে। শুধুমাত্র পরবর্তী ফ্রেমে পুনর্গঠন শুরু হয়। এটি নিশ্চিত করে যে ক্যাসকেডিং পরিবর্তনের সময় UI কয়েক ডজন বার পুনরায় আঁকা না হয়।
বৈশ্বিক এবং স্থানীয় snapshot: ডিফল্টরূপে, mutableStateOf বৈশ্বিক snapshot-এ কাজ করে যা স্বয়ংক্রিয়ভাবে প্রয়োগ হয়। আপনি Snapshot.takeSnapshot()-এর মাধ্যমে সাইড ইফেক্ট ছাড়া বিচ্ছিন্ন পড়ার জন্য একটি স্থানীয় snapshot তৈরি করতে পারেন। এটি Modifier-এর ভিতরে ব্যবহার করা হয় যখন আপনার পরিবর্তনগুলিতে সাবস্ক্রাইব না করেই State পড়ার প্রয়োজন হয়। এই পদ্ধতি কর্মক্ষমতা উন্নত করে এবং অপ্রত্যাশিত পুনর্গঠন প্রতিরোধ করে।
একটি বাস্তব দৃশ্য বিবেচনা করুন — তিনটি ফিল্ড সহ একটি লগইন ফর্ম: ইমেল, পাসওয়ার্ড এবং লোডিং অবস্থা। তিনটি ফিল্ডই mutableStateOf ব্যবহার করে, কিন্তু ভিন্ন policy এবং ভিন্ন নেস্টিং স্তরের সাথে। email প্রতিনিধিত্ব ব্যবহার করে, password সরাসরি অ্যাক্সেস ব্যবহার করে।
data class LoginState(
val email: String = "",
val password: String = "",
val isLoading: Boolean = false,
val error: String? = null
)
@Composable
fun LoginForm(onLogin: (String, String) -> Unit) {
// ফর্মের জন্য একক State, policy = referentialEquality
var formState by remember {
mutableStateOf(LoginState(), SnapshotMutationPolicy.referentialEquality())
}
val isValid = remember(formState) {
formState.email.contains("@") && formState.password.length() >= 6
}
Column(modifier = Modifier.padding(16.dp)) {
OutlinedTextField(
value = formState.email,
onValueChange = { formState = formState.copy(email = it) },
label = { Text("ইমেল") }
)
OutlinedTextField(
value = formState.password,
onValueChange = { formState = formState.copy(password = it) },
label = { Text("পাসওয়ার্ড") },
visualTransformation = PasswordVisualTransformation()
)
Button(
onClick = { onLogin(formState.email, formState.password) },
enabled = isValid
) {
Text("লগইন")
}
}
}
এই উদাহরণে, mutableStateOf একটি কাস্টম ডেটা ক্লাস LoginState এবং policy referentialEquality-এর সাথে ব্যবহার করা হয়েছে। এর মানে হল পুনর্গঠন কেবল তখনই শুরু হবে যখন copy()-এর মাধ্যমে একটি নতুন LoginState ইন্সট্যান্স অ্যাসাইন করা হয়। isValid formState-এর উপর ভিত্তি করে গণনা করা হয় এবং শুধুমাত্র যখন এটি পরিবর্তিত হয় তখনই পুনর্গণনা করা হয়। এই পদ্ধতি পুনর্গঠনের উপর স্পষ্ট নিয়ন্ত্রণ দেয়: প্রতিটি ফর্ম ফিল্ড শুধুমাত্র একটি নতুন কপি তৈরি করে পরিবর্তিত হয়।
সচরাচর জিজ্ঞাসা
mutableStateOf হল একটি Compose-নির্দিষ্ট কন্টেইনার যা snapshot-এর ভিতরে কাজ করে। StateFlow kotlinx.coroutines.flow থেকে আসে যা Compose-এর সাথে আবদ্ধ নয়। mutableStateOf স্বয়ংক্রিয়ভাবে পুনর্গঠন শুরু করে, StateFlow-এর collectAsState() প্রয়োজন। Composable-এর ভিতরে UI অবস্থার জন্য, mutableStateOf পছন্দনীয়।
হ্যাঁ, mutableStateOf Composable ফাংশনের বাইরে কল করা যেতে পারে, কিন্তু এটি ট্র্যাক করা হবে না। UI-তে প্রতিক্রিয়াশীলতার জন্য, State-কে Composable-এর ভিতরে পড়তে হবে। অনেক ViewModel StateFlow-এর মাধ্যমে UI-তে অবস্থা পাঠাতে MutableStateField (mutableStateOf-এর উপর একটি মোড়ক) ব্যবহার করে।
Snapshot সিস্টেম সামঞ্জস্য নিশ্চিত করে: প্রতিটি পুনর্গঠন snapshot শুরুর সময় একটি সামঞ্জস্যপূর্ণ অবস্থা দেখে। বিভিন্ন থ্রেড থেকে পরিবর্তনগুলি ফ্রেম সীমানায় পারমাণবিকভাবে প্রয়োগ করা হয়, একটি একক কম্পোজিশনের মধ্যে পড়ার সময় রেস কন্ডিশন দূর করে।
একটি নতুন মান অ্যাসাইন করুন: count.value = 0 (অথবা প্রতিনিধিত্ব সহ count = 0)। যদি State সম্পূর্ণরূপে পুনরায় তৈরি করার প্রয়োজন হয়, একটি কী সহ remember ব্যবহার করুন: remember(key) { mutableStateOf(initial) } — যখন কী পরিবর্তিত হয়, State নতুন করে তৈরি হবে।
Composer snapshot ব্যবহার করে যা পরিবর্তনগুলিকে গ্রুপ করে: একটি ফ্রেমে শত শত অ্যাসাইনমেন্টের সাথেও, পুনর্গঠন শুধুমাত্র একবার চলে। খুব ঘন ঘন আপডেট (অ্যানিমেশন) এর জন্য, Animatable বা animate*AsState ব্যবহার করুন — এগুলি ফ্রেম-বাই-ফ্রেম আপডেটের জন্য অপ্টিমাইজ করা।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন