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 یقینی بناتا ہے کہ وہی MutableState دوبارہ ترکیبوں کے ایک سلسلے میں زندہ رہے جب تک Composable فنکشن ترکیب میں رہتا ہے۔
@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 اور مختلف درجہ بندی کی سطحوں کے ساتھ۔ ای میل تفویض استعمال کرتا ہے، پاس ورڈ براہ راست رسائی استعمال کرتا ہے۔
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-specific کنٹینر ہے جو snapshot کے اندر کام کرتا ہے۔ StateFlow kotlinx.coroutines.flow سے آتا ہے جو Compose سے منسلک نہیں ہے۔ mutableStateOf خود بخود دوبارہ ترکیب شروع کرتا ہے، جبکہ StateFlow کو collectAsState() کی ضرورت ہوتی ہے۔ Composable کے اندر UI حالت کے لیے، mutableStateOf ترجیح ہے۔
جی ہاں، mutableStateOf کو Composable فنکشنز کے باہر بلایا جا سکتا ہے، لیکن یہ ٹریک نہیں کیا جائے گا۔ UI میں ردعمل کے لیے، State کو Composable کے اندر پڑھنا ضروری ہے۔ بہت سے ViewModel StateFlow کے ذریعے UI کو حالت پہنچانے کے لیے MutableStateField (mutableStateOf کے گرد ایک لفافہ) استعمال کرتے ہیں۔
Snapshot نظام مستقل مزاجی کو یقینی بناتا ہے: ہر دوبارہ ترکیب snapshot کے شروع میں ایک مستقل حالت دیکھتی ہے۔ مختلف تھریڈز کی تبدیلیاں فریم کی حد پر ایٹمی طور پر لاگو ہوتی ہیں، ایک ہی ترکیب کے اندر پڑھنے کے دوران race condition کو ختم کرتی ہیں۔
ایک نئی قدر تفویض کریں: count.value = 0 (یا تفویض کے ساتھ count = 0)۔ اگر آپ کو State کو مکمل طور پر دوبارہ بنانے کی ضرورت ہے تو، ایک کنجی کے ساتھ remember استعمال کریں: remember(key) { mutableStateOf(initial) } — جب کنجی بدلے گی، State نئے سرے سے بنایا جائے گا۔
Composer snapshot استعمال کرتا ہے جو تبدیلیوں کو گروپ کرتے ہیں: ایک فریم میں سینکڑوں اسائنمنٹس کے باوجود، دوبارہ ترکیب صرف ایک بار چلتی ہے۔ بہت بار بار اپ ڈیٹس (اینیمیشن) کے لیے، Animatable یا animate*AsState استعمال کریں — یہ فریم بہ فریم اپ ڈیٹس کے لیے بہتر بنائے گئے ہیں۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں