CoroutineScope ایک Kotlin انٹرفیس ہے جو کوروٹین کے لائف سائیکل کی وضاحت کرتا ہے اور نئی کوروٹین شروع کرنے کے لیے سیاق فراہم کرتا ہے۔ Kotlin دستاویزات، 2025 کے مطابق، ہر CoroutineScope مثال میں CoroutineContext ہوتا ہے اور اس کے اندر شروع کی گئی تمام کوروٹین کا انتظام کرتا ہے۔ جب scope منسوخ (cancel) ہوتا ہے، تو تمام چائلڈ کوروٹین خود بخود منسوخ ہو جاتی ہیں، جو میموری لیک کو روکتا ہے۔
اہم نکات
CoroutineScope kotlinx.coroutines لائبریری کا ایک بنیادی انٹرفیس ہے جو کوروٹین کے لیے کنٹینر کا کام کرتا ہے۔ یہ کوروٹین لائف سائیکل کی حدود کی وضاحت کرتا ہے: جب scope مکمل ہوتا ہے، تو اس کے اندر کی تمام کوروٹین خود بخود منسوخ ہو جاتی ہیں۔
public interface CoroutineScope {
public val coroutineContext: CoroutineContext
}
انٹرفیس میں صرف ایک فیلڈ ہے — coroutineContext۔ اس کے ذریعے، scope اس کے اندر شروع کی گئی تمام کوروٹین کے لیے ایک ڈسپیچر (Dispatcher)، جاب (Job)، استثنا ہینڈلر اور دیگر سیاق عناصر فراہم کرتا ہے۔
کوروٹین شروع کرنے والے تمام فنکشن — launch، async، runBlocking — CoroutineScope پر توسیعی فنکشن ہیں۔ اس کا مطلب ہے کہ انہیں صرف اس وقت کال کیا جا سکتا ہے جب scope آبجیکٹ موجود ہو۔ یہ ڈیزائن اس بات کو یقینی بناتا ہے کہ ہر کوروٹین کا واضح طور پر متعین پیرنٹ اور لائف سائیکل ہو۔
Android میں، ہر آرکیٹیکچرل کمپوننٹ کا اپنا scope ہوتا ہے: ViewModel کے لیے viewModelScope، Activity/Fragment کے لیے lifecycleScope۔ سرور ایپلیکیشن میں، scope کو HTTP درخواست یا ڈیٹابیس کنکشن پول سے منسلک کیا جا سکتا ہے۔
CoroutineScope کے اندرونی کام کو سمجھنے کے لیے Job کے تصور اور ساختی ہم وقتی کے اصول سے واقفیت ضروری ہے۔
ہر کوروٹین شروع ہونے پر ایک Job آبجیکٹ (یا async کے لیے Deferred) لوٹاتا ہے۔ Job ایک محدود لائف سائیکل والے کام کی نمائندگی کرتا ہے: New، Active، Completing، Completed، Cancelling، Cancelled۔ Job آبجیکٹ ایک درخت کی ساخت بناتے ہیں:
ساختی ہم وقتی Kotlin Coroutines کا ایک اہم آرکیٹیکچرل اصول ہے، جس میں کوروٹین کا لائف سائیکل اس کے scope کے لائف سائیکل سے منسلک ہوتا ہے۔ یہ “فائر اینڈ فارگیٹ” ماڈل کے برعکس ہے، جہاں scope مکمل ہونے کے بعد بھی کوروٹین زندہ رہتا ہے۔ ساختی ہم وقتی کے فوائد:
جب scope.cancel() کال کیا جاتا ہے، scope کا Job Cancelled حالت میں چلا جاتا ہے، جو تمام چائلڈ Job کو بار بار منسوخ کرتا ہے۔ منسوخی کے بعد، scope صرف نیا CoroutineScope مثال بنا کر ہی دوبارہ استعمال کیا جا سکتا ہے۔
آپ CoroutineScope کو فیکٹری فنکشن کے ذریعے یا اپنی کلاس میں انٹرفیس لاگو کر کے بنا سکتے ہیں۔ دونوں طریقوں کو دیکھتے ہیں۔
val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
scope.launch {
println("Running on ${Thread.currentThread().name}")
}
فیکٹری فنکشن CoroutineContext لیتا ہے اور مخصوص سیاق کے ساتھ scope بناتا ہے۔ مثال CPU-گہرے کاموں کے لیے Dispatchers.Default اور SupervisorJob استعمال کرتی ہے، جو چائلڈ کوروٹین کے درمیان استثنا کو الگ کرتا ہے۔
class MyRepository {
private val scope = CoroutineScope(Dispatchers.IO + Job())
suspend fun fetchData(): Data = scope.async {
api.getData()
}.await()
fun cleanup() {
scope.cancel()
}
}
ہم scope کو کلاس فیلڈ کے طور پر محفوظ کرتے ہیں اور اسے منسوخ کرنے کے لیے دستی طور پر cleanup کال کرتے ہیں۔ یہ طریقہ منظم لائف سائیکل والے کمپوننٹ — جیسے ریپوزٹری یا مینیجر — کے لیے موزوں ہے۔
Kotlin by کلیدی لفظ کے ذریعے CoroutineScope کے نفاذ کو ڈیلیگیٹ کرنے کی اجازت دیتا ہے:
class DataLoader : CoroutineScope by CoroutineScope(Dispatchers.IO) {
fun load() {
launch {
// coroutine runs in DataLoader scope
}
}
}
یہ طریقہ اس وقت مفید ہے جب کلاس خود ایک scope ہو اور کوروٹین شروع کرنے کے طریقے فراہم کرنا چاہے۔ تاہم محتاط رہیں: کلاس CoroutineScope کے تمام طریقے (cancel سمیت) وراثت میں لے لیتی ہے، جو encapsulation کو توڑ سکتا ہے۔
GlobalScope پوری ایپلیکیشن کے لیے ایک سنگلٹن CoroutineScope ہے۔ پروڈکشن کوڈ میں اس کا استعمال سرکاری طور پر تجویز نہیں کیا جاتا۔
JetBrains GlobalScope کو صرف نایاب منظرناموں میں اجازت دیتا ہے: ایپلیکیشن سطح کے پس منظر کے عمل جو تمام Activity بند ہونے کے بعد بھی چلنے چاہئیں (جیسے ڈیٹا سنکرونائزیشن، تجزیات)۔ لیکن ان صورتوں میں بھی، CoroutineScope(SupervisorJob()) کے ساتھ اپنا scope بنانا بہتر ہے۔
واضح لائف سائیکل انتظام کے ساتھ ہمیشہ کسٹم CoroutineScope استعمال کریں۔ Android میں، یہ viewModelScope اور lifecycleScope ہیں۔ سرور ایپلیکیشن میں، ہر درخواست یا کنکشن پول کے لیے scope بنائیں۔
دونوں فنکشن معطل فنکشن ہیں جو متوازی کاموں کے لیے عارضی scope بناتے ہیں، لیکن استثنا کے ساتھ ان کا رویہ بنیادی طور پر مختلف ہے۔
| خصوصیت | coroutineScope | supervisorScope |
|---|---|---|
| غلطی پر رویہ | چائلڈ کوروٹین میں استثنا باقی سب کو منسوخ کرتا ہے | چائلڈ کوروٹین میں استثنا باقیوں کو منسوخ نہیں کرتا |
| غلطی کا پھیلاؤ | ہاں، پہلا استثنا باہر پھیلتا ہے | ہاں، پہلا استثنا باہر پھیلتا ہے |
| ڈیفالٹ Job | Job() — چائلڈ پیرنٹ سے منسلک | SupervisorJob() — چائلڈ ایک دوسرے پر منحصر نہیں |
| عام استعمال کی صورت | متعدد مراحل کا ایٹمی عمل | آزاد متوازی کام (UI لوڈ) |
coroutineScope استعمال کریں جب متعدد متوازی کارروائیاں ایک واحد ایٹمی عمل تشکیل دیں۔ مثال کے طور پر، تین سرورز سے ڈیٹا لوڈ کرنا: اگر ایک درخواست ناکام ہو، باقی بے معنی ہیں۔
suspend fun loadProductPage(): ProductPage = coroutineScope {
val product = async { api.getProduct() }
val reviews = async { api.getReviews() }
ProductPage(product.await(), reviews.await())
}
اگر getProduct یا getReviews استثنا پھینکتا ہے — دونوں کوروٹین منسوخ ہو جاتی ہیں اور استثنا کالر کوڈ میں پھیل جاتا ہے۔
supervisorScope استعمال کریں جب متوازی کارروائیاں ایک دوسرے پر منحصر نہ ہوں۔ مثال کے طور پر، متعدد آزاد حصوں میں پروفائل ڈیٹا لوڈ کرنا: اگر سفارشات کا حصہ ناکام ہو، پروفائل ہیڈر اور دوستوں کی فہرست ظاہر ہونی چاہیے۔
Kotlin میں CoroutineScope استعمال کرتے وقت ڈویلپرز کی سب سے عام غلطیوں پر نظر ڈالتے ہیں۔
کوروٹین لیک کا سب سے عام منظرنامہ کمپوننٹ ختم ہونے پر cancel کال کیے بغیر scope بنانا ہے۔ اگر scope منسوخ نہیں کیا گیا، کوروٹین چلتی رہتی ہیں، اشیاء کے حوالے رکھتی ہیں۔ Android میں، viewModelScope یا lifecycleScope استعمال کریں، جو خود بخود منسوخ ہو جاتے ہیں۔
GlobalScope Android کمپوننٹ لائف سائیکل کو نظر انداز کرتا ہے۔ Activity بند ہونے کے بعد GlobalScope میں شروع کی گئی کوروٹین چلتی رہے گی اور UI کو اپ ڈیٹ کرنے کی کوشش کرے گی — جو کریش کا سبب بنے گی۔ UI کمپوننٹ کے لیے ہمیشہ lifecycleScope استعمال کریں۔
cancel() کال کرنے کے بعد، scope دوبارہ استعمال نہیں کیا جا سکتا — اس کے اندر کی تمام کوروٹین پہلے ہی مکمل ہو چکی ہیں۔ فیکٹری فنکشن کے ذریعے نیا CoroutineScope مثال بنائیں۔ Job() دوبارہ فعال کرنے کی حمایت نہیں کرتا۔
by سے ڈیلیگیٹ کرنے پر، کلاس کو عوامی cancel() طریقہ ملتا ہے جو کہیں سے بھی کال کیا جا سکتا ہے، encapsulation توڑتا ہے۔ انٹرفیس ڈیلیگیٹ کرنے کے بجائے scope کو نجی فیلڈ کے طور پر محفوظ کریں۔
اکثر پوچھے گئے سوالات
CoroutineScope ایک انٹرفیس ہے جو CoroutineContext کا مالک ہے اور کوروٹین لائف سائیکل کا ذمہ دار ہے۔ CoroutineContext عناصر (ڈسپیچر، job، غلطی ہینڈلر) کا ایک مجموعہ ہے جو یہ طے کرتا ہے کہ کوروٹین “کیسے” عمل میں آتی ہے۔ ایک فرق: scope کوروٹین بناتا ہے، جبکہ سیاق ان کے رویے کو کنٹرول کرتا ہے۔
ہاں، یہ ایک معیاری پیٹرن ہے: CoroutineScope(Dispatchers.IO + SupervisorJob())۔ SupervisorJob ایک چائلڈ کوروٹین میں استثنا ہونے پر باقیوں کی جھڑی دار منسوخی کو روکتا ہے۔ یہ آزاد متوازی کاموں کے لیے مفید ہے جہاں ایک میں غلطی دوسروں کو نہیں روکنا چاہیے۔
scope میں کوروٹین کی تعداد کی کوئی حد نہیں — وہ صرف دستیاب میموری اور ڈسپیچر کی ترتیبات سے محدود ہیں۔ عملی حد عام طور پر ایک scope میں ہزاروں فعال کوروٹین ہوتی ہے۔ تاہم، بڑی تعداد میں کوروٹین آرکیٹیکچرل مسائل کی نشاندہی کر سکتی ہے۔
صحیح طریقہ یہ ہے کہ کنسٹرکٹر کے ذریعے کلاس میں scope پاس کریں یا kotlinx-coroutines-test سے runBlockingTest / runTest استعمال کریں۔ ٹیسٹ میں، آپ scope کو TestCoroutineDispatcher سے بدل سکتے ہیں اور دستی طور پر کوروٹین پر عملدرآمد کو کنٹرول کر سکتے ہیں۔
نہیں، scope کوروٹین کے لیے ایک بیرونی کنٹینر ہے۔ کوروٹین خود scope نہیں ہے۔ تاہم، کوروٹین کے اندر آپ coroutineScope یا supervisorScope کے ذریعے چائلڈ کوروٹین کو متوازی چلانے کے لیے نیا scope بنا سکتے ہیں۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں