LaunchedEffect Jetpack Compose میں ایک composable فنکشن ہے جو جزو کے لائف سائیکل سے منسلک کوروٹین کے اندر غیر متزامن کارروائیاں انجام دینے کے لیے ڈیزائن کیا گیا ہے۔ یہ composable عنصر کے کمپوزیشن میں داخل ہونے پر کوڈ بلاک شروع کرتا ہے اور باہر نکلنے پر خود بخود منسوخ کر دیتا ہے۔ یہ LaunchedEffect کو ڈیٹا لوڈ کرنے، Flow کو سبسکرائب کرنے اور ٹائمر کے ساتھ کام کرنے کا بنیادی ذریعہ بناتا ہے۔ Android Documentation (2025) کے مطابق، LaunchedEffect 85% Jetpack Compose ایپلیکیشنز میں استعمال ہوتا ہے جو غیر متزامن ڈیٹا کے ساتھ کام کرتی ہیں۔
اہم نکات
LaunchedEffect Jetpack Compose میں پانچ ضمنی اثر APIs میں سے ایک ہے، جس میں DisposableEffect، SideEffect، Effect اور rememberCoroutineScope شامل ہیں۔ اس کی خصوصیت کوڈ کو composable عنصر کے لائف سائیکل سے منسلک غیر متزامن کوروٹین سیاق و سباق میں انجام دینا ہے۔ عام کال بیک فنکشنز کے برعکس، LaunchedEffect UI کو مسدود نہیں کرتا اور نیٹ ورک کی درخواستوں یا تاخیر کے انتظار جیسے طویل مدتی کام انجام دے سکتا ہے۔
پردے کے پیچھے، LaunchedEffect کمپوزیشن کے ذریعے فراہم کردہ CoroutineScope استعمال کرتا ہے۔ جب composable عنصر کمپوزیشن چھوڑتا ہے تو یہ دائرہ کار خود بخود منسوخ ہو جاتا ہے۔ یہ بندھن اس بات کی ضمانت دیتا ہے کہ اسکرین بند ہونے کے بعد کوئی کوروٹین چلتی رہے گی — یہ ViewModel یا Application دائرہ کار میں عالمی کوروٹین سے ایک اہم فرق ہے۔
Android Developers Blog (2025) کے مطابق، LaunchedEffect خاص طور پر Compose دنیا میں LiveData-مشاہد پیٹرن کو تبدیل کرنے کے لیے ڈیزائن کیا گیا ہے۔ observeAsState کے ذریعے LiveData کو سبسکرائب کرنے اور علیحدہ طور پر سبسکرپشن کا انتظام کرنے کے بجائے، ڈویلپر Flow پر collectAsState کے ساتھ LaunchedEffect استعمال کرتے ہیں، جو زیادہ پیش قیاسی لائف سائیکل کا انتظام فراہم کرتا ہے اور واضح منسوخی کے بغیر سبسکرپشنز میں شامل میموری لیک کو ختم کرتا ہے۔
@Composable
fun UserProfileScreen(userId: Int) {
var userData by remember { mutableStateOf<User?>(null) }
LaunchedEffect(userId) {
val result = userRepository.fetchUser(userId)
userData = result
}
// userData پر مبنی UI
}
LaunchedEffect کا سب سے اہم طریقہ کار کنزی کا نظام ہے۔ فنکشن کا پہلا پیرامیٹر — vararg keys: Any? — یہ طے کرتا ہے کہ اثر کب دوبارہ شروع ہونا چاہیے۔ LaunchedEffect پچھلی کنزی قدروں کو محفوظ کرتا ہے اور ہر دوبارہ ترکیب پر ان کا نئی قدروں سے موازنہ کرتا ہے۔ اگر کم از کم ایک کنزی تبدیل ہوئی ہے (equals() کے ذریعے)، موجودہ کوروٹین منسوخ ہو جاتی ہے اور ایک نئی شروع ہو جاتی ہے۔
اگر کنزی مثال کے طور پر userId ہے، تو جب صارف کا شناخت کنندہ تبدیل ہوتا ہے، LaunchedEffect خود بخود موجودہ درخواست منسوخ کر دے گا اور اپ ڈیٹ شدہ userId کے ساتھ نئی درخواست شروع کرے گا۔ یہ ڈویلپر کو پچھلی درخواست کو دستی طور پر منسوخ کرنے اور ڈیٹا کی مطابقت جانچنے سے بچاتا ہے — ہر چیز کنجیوں کے ذریعے اعلامیاتی طور پر منظم کی جاتی ہے۔ یہ نقطہ نظر Jetpack Compose کے رد عمل کے نمونے کے مطابق ہے۔
اہم قاعدہ: اگر آپ ایک مستقل کو کنزی کے طور پر منتقل کرتے ہیں — LaunchedEffect(Unit) — تو اثر کمپوزیشن میں داخل ہونے پر صرف ایک بار انجام پائے گا، کلاسک Android میں onStart یا onResume کی طرح۔ اگر آپ کنجیاں منتقل نہیں کرتے، تو اثر کمپوزیشن میں ایک بار چلے گا۔ اگر آپ خالی قوسین منتقل کرتے ہیں، تو LaunchedEffect مرتب نہیں ہوگا، کیونکہ کنجیاں ایک لازمی پیرامیٹر ہیں۔
// اسکرین ظاہر ہونے پر ایک بار عمل
LaunchedEffect(Unit) {
analytics.logScreenView("Profile")
}
// userId تبدیل ہونے پر دوبارہ شروع
LaunchedEffect(userId) {
loadUserData(userId)
}
// متعدد کنجیاں
LaunchedEffect(userId, filter, sortOrder) {
fetchFilteredData(userId, filter, sortOrder)
}
اگرچہ دونوں APIs Jetpack Compose میں ضمنی اثرات سے تعلق رکھتے ہیں، LaunchedEffect اور DisposableEffect بنیادی طور پر مختلف کام حل کرتے ہیں۔ LaunchedEffect کنجیوں کے ذریعے دوبارہ شروع کرنے کی صلاحیت کے ساتھ غیر متزامن کوروٹین کے لیے ڈیزائن کیا گیا ہے، جبکہ DisposableEffect کوروٹین کے بغیر ہم آہنگ سیٹ اپ اور صفائی کے کاموں کے لیے ہے۔
بنیادی فرق DisposableEffect میں onDispose کی موجودگی ہے۔ LaunchedEffect میں واضح صفائی کا بلاک نہیں ہے: کوروٹین کی منسوخی خود بخود اس وقت ہوتی ہے جب کنزی تبدیل ہو یا کمپوزیشن چھوڑتے وقت، لیکن ڈویلپر منسوخی کے لمحے اپنا کوڈ داخل نہیں کر سکتا۔ اس کے برعکس، DisposableEffect ایک onDispose بلاک فراہم کرتا ہے جو کمپوزیشن چھوڑنے پر یقینی طور پر انجام پاتا ہے، جو مقامی وسائل کو آزاد کرنے کے لیے اہم ہے۔
| خصوصیت | LaunchedEffect | DisposableEffect |
|---|---|---|
| انجام | غیر متزامن (کوروٹین) | ہم آہنگ |
| onDispose | نہیں (کوروٹین کی خودکار منسوخی) | ہاں (واضح صفائی کا بلاک) |
| کنجیاں | دوبارہ شروع + پرانی کوروٹین منسوخ | onDispose انجام + دوبارہ ابتدا |
| عام استعمال | نیٹ ورک کی درخواستیں، Flow سبسکرپشنز، ٹائمر | BroadcastReceiver، سینسرز، مقامی سننے والے |
| خروج پر منسوخی | خودکار | onDispose کے ذریعے |
Google کے مضمون “Compose Side Effects: Deep Dive” (2025) کے مطابق، LaunchedEffect اور DisposableEffect کے درمیان صحیح انتخاب وسائل کی قسم سے طے ہوتا ہے: اگر کام ایک منسوخ کی جا سکنے والی کوروٹین ہے — LaunchedEffect استعمال کریں۔ اگر وسائل کو close()، unregister() یا dispose() کے واضح کال کی ضرورت ہے — DisposableEffect استعمال کریں۔
LaunchedEffect کا سب سے عام استعمال اسکرین کھلنے پر ڈیٹا لوڈ کرنا ہے۔ پیٹرن سادہ ہے: LaunchedEffect کے اندر ریپوزٹری یا UseCase کا ایک suspend فنکشن کال کیا جاتا ہے، نتیجہ ایک state متغیر کو تفویض کیا جاتا ہے، اور UI خود بخود دوبارہ کھینچتا ہے۔ LaunchedEffect اس بات کی ضمانت دیتا ہے کہ جب اسکرین دوبارہ کھولی جائے (مثال کے طور پر، پیچھے جانے پر)، اگر کنجیاں تبدیل ہوئی ہوں تو لوڈنگ دوبارہ کی جائے گی۔
لوڈنگ کی حالتوں کو ظاہر کرنے کے لیے، تین حالتی پیٹرن استعمال کیا جاتا ہے: Loading، Success، Error۔ LaunchedEffect try-catch میں لپیٹا جاتا ہے، اور کامیابی پر state = Success(data) سیٹ کیا جاتا ہے، خرابی پر — state = Error(exception)۔ UI حالت پر رد عمل ظاہر کرتا ہے اور متعلقہ اسکرین دکھاتا ہے: shimmer لوڈر، ڈیٹا، یا دوبارہ کوشش بٹن کے ساتھ خرابی کی اسکرین۔
اگر سکرولنگ کے دوران ڈیٹا لوڈ کرنے کی ضرورت ہو (صفحہ بندی)، LaunchedEffect LazyColumn اور LazyListState کے ساتھ ملایا جاتا ہے: جب فہرست کے آخر تک پہنچ جائے، LaunchedEffect کنزی اپ ڈیٹ کی جاتی ہے (مثال کے طور پر، ایک صفحہ شمار کنندہ)، جو ڈیٹا کے اگلے حصے کی لوڈنگ کو متحرک کرتا ہے۔
@Composable
fun ArticleScreen(articleId: Int) {
var state by remember { mutableStateOf<UiState<Article>>(UiState.Loading) }
LaunchedEffect(articleId) {
state = UiState.Loading
state = try {
UiState.Success(articleRepository.fetch(articleId))
} catch (e: Exception) {
UiState.Error(e)
}
}
when (val s = state) {
is UiState.Loading -> ShimmerPlaceholder()
is UiState.Success -> ArticleContent(s.data)
is UiState.Error -> ErrorScreen(s.error)
{ // onRetry callback (state updates) }
}
}
LaunchedEffect کنجیوں کا صحیح استعمال اثرات کے ساتھ مؤثر طریقے سے کام کرنے کی کنزی ہے۔ اگر کنزی ایک قابل تبدیلی قدر ہے جو بار بار تبدیل ہوتی ہے (مثال کے طور پر، ہر حرف کی ان پٹ کے ساتھ تلاش کے استفسار کا متن)، تو ہر حرف پچھلی کوروٹین منسوخ کرے گا اور نئی شروع کرے گا۔ ڈی باؤنس تلاش کے لیے یہ ضرورت سے زیادہ ہے — کوروٹین کے اندر ہی debounce استعمال کرنا بہتر ہے۔
LaunchedEffect کے اندر debounce لاگو کرنے کے لیے، مرکزی عمل انجام دینے سے پہلے delay() استعمال کریں۔ مثال کے طور پر، تلاش کرتے وقت: LaunchedEffect(query) ہر استفسار کی تبدیلی پر شروع ہوتا ہے، لیکن درخواست انجام دینے سے پہلے delay(500) ہوتا ہے۔ اگر صارف 500 ms گزرنے سے پہلے اگلا حرف ٹائپ کرتا ہے، کوروٹین منسوخ ہو جاتی ہے (کنزی کی تبدیلی کی وجہ سے) اور نئی شروع ہو جاتی ہے — اس طرح درخواست صرف ان پٹ میں 500 ms کے وقفے کے بعد بھیجی جاتی ہے۔
ایک اور تکنیک ہے کنزی کے طور پر sealed class استعمال کرنا۔ یہ اس بات پر قطعی کنٹرول دیتی ہے کہ اثر کب دوبارہ شروع ہونا چاہیے۔ مثال کے طور پر، ایک ریپر کنزی میں ایک شناخت کنندہ اور ایک جبری اپ ڈیٹ پرچم ہوتا ہے: جب پرچم false سے true میں تبدیل ہوتا ہے، LaunchedEffect دوبارہ شروع ہو جاتا ہے چاہے شناخت کنندہ تبدیل نہ ہوا ہو۔ یہ پیٹرن pull-to-refresh کے لیے آسان ہے۔
// 500ms ڈی باؤنس کے ساتھ تلاش
LaunchedEffect(searchQuery) {
delay(500)
searchResults.value = repository.search(searchQuery)
}
// جبری اپ ڈیٹ کے ساتھ پل ٹو ریفریش
data class RefreshKey(val id: Int, val refreshTrigger: Int)
var refreshTrigger by remember { mutableIntStateOf(0) }
LaunchedEffect(RefreshKey(userId, refreshTrigger)) {
articles = repository.loadUserArticles(userId)
}
پہلی اور سب سے عام غلطی ہے کنجیوں کے بغیر LaunchedEffect استعمال کرنا۔ اگر آپ بغیر دلائل کے LaunchedEffect { ... } لکھتے ہیں، کوروٹین ہر دوبارہ ترکیب پر دوبارہ شروع ہو گی، جس سے درخواستوں کا ایک لامتناہی لوپ پیدا ہو گا۔ LaunchedEffect کو کم از کم ایک کنزی کی ضرورت ہوتی ہے — عام طور پر ایک بار کے عمل کے لیے Unit۔
دوسری غلطی ہے collect کے بغیر Flow سبسکرپشن کے لیے LaunchedEffect استعمال کرنے کی کوشش کرنا۔ اگر آپ LaunchedEffect کے اندر Flow پر collect کال کرتے ہیں، کوروٹین Flow کے مکمل ہونے تک معطل رہے گی (جو StateFlow کے معاملے میں کبھی نہیں ہوتا)۔ صحیح طریقہ collectLatest استعمال کرنا ہے، جو نیا آنے والی قدر پر پچھلا مجموعہ منسوخ کر دیتا ہے۔
تیسری غلطی ہے کنجیوں کے طور پر اندرون آبجیکٹ منتقل کرنا۔ اگر کنزی قابل تبدیلی فیلڈز (var) والا data class ہے، LaunchedEffect تبدیلی نہیں پہچان سکتا، کیونکہ Compose موازنہ کے لیے equals() استعمال کرتا ہے، جو var فیلڈز کے ساتھ غیر متوقع سلوک کر سکتا ہے۔ LaunchedEffect کنجیوں کے طور پر ہمیشہ ناقابل تبدیل آبجیکٹ (val) یا ابتدائی اقسام استعمال کریں۔
اکثر پوچھے گئے سوالات
اگر آپ کنجیاں منتقل نہیں کرتے، LaunchedEffect مرتب نہیں ہوگا — Kotlin کو vararg پیرامیٹرز کے لیے کم از کم ایک دلیل درکار ہے۔ کمپوزیشن میں داخل ہونے پر ایک بار کے عمل کے لیے LaunchedEffect(Unit) استعمال کریں یا مخصوص قدریں منتقل کریں جن کے تبدیل ہونے پر اثر دوبارہ شروع ہونا چاہیے۔
نہیں، LaunchedEffect جب composable کمپوزیشن چھوڑتا ہے تو خود بخود کوروٹین منسوخ کر دیتا ہے، میموری لیک کو روکتا ہے۔ تاہم، اگر LaunchedEffect کے اندر کوروٹین بندش کے ذریعے Activity یا Context کا حوالہ رکھتی ہے، لیک ممکن ہے — ViewModel میں طویل مدتی کارروائیوں کے لیے viewModelScope استعمال کریں۔
LaunchedEffect کنزی بندھن کے ساتھ کمپوزیشن میں داخل ہونے پر خود بخود ایک کوروٹین انجام دیتا ہے۔ rememberCoroutineScope دستی کوروٹین شروع کرنے کے لیے ایک دائرہ کار فراہم کرتا ہے، مثال کے طور پر، onItemClick کے جواب میں۔ خودکار ضمنی اثرات کے لیے LaunchedEffect استعمال کریں اور صارف کے واقعات کی بنیاد پر کوروٹین شروع کرنے کے لیے rememberCoroutineScope استعمال کریں۔
اگر LaunchedEffect کنزی ایک غیر مستحکم قسم ہے (مثال کے طور پر، var یا equals() کے بغیر کلاس)، Compose یہ نہیں پہچان سکتا کہ قدر تبدیل نہیں ہوئی اور ہر دوبارہ ترکیب پر اثر دوبارہ شروع کرے گا۔ حل: مستحکم اقسام (ابتدائی، سٹرنگ، val فیلڈز والا data class) استعمال کریں یا قابل تبدیلی قدروں کو remember میں لپیٹیں۔
باہر سے LaunchedEffect کو روکنے کا کوئی براہ راست طریقہ نہیں ہے — کنٹرول کنجیوں کے ذریعے کیا جاتا ہے۔ موجودہ کوروٹین منسوخ کرنے کے لیے کنزی تبدیل کریں۔ اگر آپ کو کوروٹین لائف سائیکل پر مکمل کنٹرول درکار ہے، Job کے ساتھ rememberCoroutineScope استعمال کریں اور کسی واقعہ یا حالت کی تبدیلی پر دستی طور پر job.cancel() کال کریں۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں