Deferred Navigation (موخر نیویگیشن) ایک ایسا نمونہ ہے جس میں اگلی اسکرین پر منتقلی ایک غیر متزامن آپریشن مکمل ہونے کے بعد ہوتی ہے، نہ کہ براہ راست صارف کے عمل کے لمحے میں۔ Android Developers (2024) کے مطابق، موخر نیویگیشن نیویگیشن اور ڈیٹا لوڈنگ کے درمیان ریس کنڈیشن سے بچنے میں مدد دیتی ہے اور پش نوٹیفکیشنز اور ڈیپ لنکس سے منتقلی کی پروسیسنگ کو آسان بناتی ہے۔ کلیدی فرق — روٹ کا حساب تمام ضروری ڈیٹا دستیاب ہونے کے بعد لگایا جاتا ہے۔
اہم نکات
Deferred Navigation (موخر نیویگیشن) ایک آرکیٹیکچرل نمونہ ہے جہاں نیویگیشن کا فیصلہ اس وقت تک موخر کیا جاتا ہے جب تک تمام ضروری ڈیٹا دستیاب نہ ہو جائے۔ براہ راست منتقلی کے برعکس جہاں صارف ایک بٹن دباتا ہے اور فوری طور پر نئی اسکرین پر پہنچ جاتا ہے، موخر نیویگیشن ٹریگر ایونٹ اور حقیقی منتقلی کو الگ کرتی ہے، ان کے درمیان ایک غیر متزامن آپریشن رکھ کر۔
آرکیٹیکچرل طور پر، Deferred Navigation حالت کی تبدیلی پر مبنی ہے: بٹن دبانا ایک غیر متزامن عمل شروع کرتا ہے، اور اس کے نتیجے کی سبسکرپشن نیویگیشن کو متحرک کرتی ہے۔ یہ MVVM یا MVI آرکیٹیکچر والی ایپلیکیشنز میں خاص طور پر اہم ہے، جہاں ViewModel حالت کا انتظام کرتی ہے اور View (Activity, Fragment, SwiftUI View) تبدیلیوں کو سبسکرائب کرتی ہے اور منتقلی کے ساتھ ردعمل دیتی ہے۔ یہ نقطہ نظر UI اور نیویگیشن منطق کے درمیان براہ راست انحصار کو ختم کرتا ہے۔
Google I/O 2023 کے مطابق، موخر نیویگیشن ان تمام منظرناموں کے لیے تجویز کی جاتی ہے جہاں نیویگیشن نیٹ ورک کی درخواست، تصدیقی جانچ، کنفیگریشن لوڈنگ یا اجازتوں کے نتیجے پر منحصر ہو۔ ڈیپ لنکس کی پروسیسنگ کے وقت بھی یہ نمونہ لازمی ہے، جہاں ایپلیکیشن کو پہلے شروع ہونا چاہیے، روٹ اسکرین لوڈ کرنی چاہیے اور اس کے بعد ہی ٹارگٹ روٹ پر جانا چاہیے۔
Deferred Navigation ان منظرناموں میں استعمال ہوتی ہے جہاں براہ راست نیویگیشن غلط اسکرین حالت یا لوڈنگ کی خرابیوں کا باعث بنتی ہے۔ آئیے چار اہم معاملات کا جائزہ لیں جہاں موخر نیویگیشن ضروری ہے۔
اگر صارف محفوظ مواد کو تھپتھپاتا ہے تو ایپلیکیشن کو پہلے رسائی ٹوکن کی جانچ کرنی چاہیے۔ اگر ٹوکن کی میعاد ختم ہو گئی ہو تو مواد کی اسکرین پر براہ راست نیویگیشن خالی اسکرین یا 401 غلطی کا باعث بنے گی۔ موخر نیویگیشن ٹوکن کی جانچ کرتی ہے، اور صرف کامیابی پر — ٹارگٹ اسکرین پر جاتی ہے۔ ناکامی پر — لاگ ان اسکرین پر ری ڈائریکٹ کرتی ہے۔
جب کوئی ایپلیکیشن بیرونی لنک کے ذریعے کھولی جاتی ہے، تو پہلے روٹ اسکرین لوڈ کرنی ہوتی ہے، نیویگیشن کی حالت بحال کرنی ہوتی ہے اور اس کے بعد ہی ڈیپ لنک منتقلی انجام دینی ہوتی ہے۔ روٹ سیاق و سباق کے بغیر ٹارگٹ اسکرین پر براہ راست نیویگیشن بے قاعدگیوں کا باعث بنے گی: خالی نیویگیشن اسٹیک یا ٹوٹا ہوا بیک اسٹیک۔
پش نوٹیفکیشن کو تھپتھپاتے وقت، ایپلیکیشن تین حالتوں میں سے ایک میں ہو سکتی ہے: بند، پس منظر میں یا فعال۔ Deferred Navigation ایپلیکیشن کی حالت کا تعین کرتی ہے، ضروری مواد لوڈ کرتی ہے اور اس کے بعد ہی ٹارگٹ اسکرین دکھاتی ہے۔ iOS UNNotificationContentExtension کے ذریعے اس منظر نامے کی پروسیسنگ کی اجازت دیتا ہے۔
اگر اسکرین کی فعالیت سرور سے فیچر فلیگ کے ذریعے کنٹرول ہوتی ہے، تو موخر نیویگیشن پہلے کنفیگریشن کی درخواست کرنے اور اس کے بعد ہی اسکرین دکھانے کی اجازت دیتی ہے۔ اگر فیچر غیر فعال ہے — صارف خالی اسکرین کے بجائے متبادل مواد یا پلیس ہولڈر دیکھتا ہے۔
| منظر نامہ | براہ راست نیویگیشن | Deferred Navigation |
|---|---|---|
| اختیار | میعاد ختم ٹوکن کے ساتھ خالی اسکرین | لاگ ان پر ری ڈائریکٹ |
| ڈیپ لنک | ٹوٹا ہوا بیک اسٹیک | صحیح نیویگیشن اسٹیک |
| پش | سیاق و سباق کے بغیر لوڈنگ | منتقلی سے پہلے ڈیٹا تیار |
| فیچر فلیگ | غیر دستیاب فعالیت دکھانا | پلیس ہولڈر یا متبادل |
براہ راست نیویگیشن ایک روایتی نقطہ نظر ہے جہاں کسی واقعہ کے جواب میں فوری طور پر منتقلی کی جاتی ہے۔ صارف ایک بٹن دباتا ہے اور UI راؤٹر فوری طور پر اسکرین تبدیل کر دیتا ہے۔ یہ نقطہ نظر سادہ اور پیش قیاسی ہے لیکن ان منظرناموں میں محدود ہے جہاں سرور سے ڈیٹا یا شرائط کی جانچ کی ضرورت ہوتی ہے۔
Deferred Navigation غیر متزامن حالت کی شکل میں ایک پرت شامل کرتی ہے۔ صارف کا واقعہ ایک آپریشن شروع کرتا ہے، اور نتیجے کی سبسکرپشن نیویگیشن کو کنٹرول کرتی ہے۔ یہ کوڈ کی پیچیدگی بڑھاتا ہے لیکن لچک فراہم کرتا ہے: ایک ہی ٹریگر لوڈ کردہ ڈیٹا کے لحاظ سے مختلف اسکرینوں پر لے جا سکتا ہے۔
دو نقطہ نظر کے درمیان انتخاب کا انحصار ضروریات پر ہے: اگر اسکرین دکھانے کے لیے غیر متزامن ڈیٹا کی ضرورت نہیں ہے — براہ راست نیویگیشن استعمال کریں۔ اگر اسکرین کسی درخواست، اختیار یا بیرونی شرائط کے نتیجے پر منحصر ہے — موخر نیویگیشن ضروری ہے۔ ایک ہائبرڈ نقطہ نظر، جہاں کچھ منتقلیاں براہ راست اور کچھ موخر ہیں، صنعتی ایپلیکیشنز میں سب سے عام عمل ہے۔
Android Jetpack آرکیٹیکچر کی سطح پر Deferred Navigation کو لاگو کرنے کے لیے میکانزم فراہم کرتا ہے۔ بنیادی خیال — ViewModel حالت کا انتظام کرتی ہے، جبکہ Activity یا Fragment تبدیلیوں کو سبسکرائب کرتی ہے اور NavController کے ذریعے نیویگیشن کو متحرک کرتی ہے۔
StateFlow Kotlin کوروٹینز میں موخر نیویگیشن کے لیے مثالی ٹول ہے۔ ViewModel نیویگیشن واقعہ کے ساتھ StateFlow کو اپ ڈیٹ کرتی ہے، اور Activity اسے دیکھتی ہے اور منتقلی انجام دیتی ہے۔ جب واقعہ پروسیس ہو جاتا ہے، StateFlow صاف ہو جاتا ہے، بار بار نیویگیشن کو روکتا ہے۔
class MainViewModel : ViewModel() {
private val _navigation = MutableSharedFlow<NavigationEvent>()
val navigation: SharedFlow<NavigationEvent> = _navigation
fun onDeepLinkReceived(link: String) {
viewModelScope.launch {
val data = resolveDeepLink(link)
_navigation.emit(NavigationEvent.GoToScreen(data))
}
}
}
Activity میں، نیویگیشن کی سبسکرپشن ViewModel سے روٹ کے ساتھ NavController کو متحرک کرتی ہے۔ اسکرین گھمانے پر بار بار نیویگیشن کو روکنے کے لیے، ایک NavigationEventWrapper ریپر استعمال کیا جاتا ہے جو واقعہ کو صرف ایک بار پروسیس کرتا ہے۔ Jetpack Navigation 2.7+ محفوظ قسم کے آرگیومنٹ پاسنگ کے لیے Safe Args کو سپورٹ کرتا ہے۔
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val vm: MainViewModel by viewModels()
repeatOnLifecycle(Lifecycle.State.STARTED) {
vm.navigation.collect { event ->
when (event) {
is NavigationEvent.GoToScreen ->
findNavController(R.id.nav_host)
.navigate(event.route)
}
}
}
}
}
iOS میں Android Jetpack کی طرح کوئی بلٹ ان Navigation Component نہیں ہے، اس لیے ڈویلپرز Combine یا async/await کے ساتھ Coordinator Pattern کے ذریعے Deferred Navigation کو لاگو کرتے ہیں۔ Coordinator اسکرین اسٹیک کا انتظام کرتا ہے اور لوڈ کردہ ڈیٹا کی بنیاد پر نیویگیشن کے فیصلے کرتا ہے۔
Coordinator ایک آبجیکٹ ہے جو ViewControllers کے درمیان نیویگیشن کا انتظام کرتا ہے۔ Combine کے ساتھ، ViewModel PassthroughSubject کے ذریعے واقعات شائع کرتی ہے، اور Coordinator انہیں سبسکرائب کرتا ہے اور منتقلی انجام دیتا ہے۔ یہ نقطہ نظر UI کو نیویگیشن منطق سے مکمل طور پر الگ کرتا ہے اور ایپلیکیشن آرکیٹیکچر کے لیے Apple کی سفارشات پر عمل کرتا ہے۔
final class AppCoordinator {
private var cancellables = Set<AnyCancellable>()
func start(viewModel: MainViewModel) {
viewModel.$navigationDestination
.compactMap { $0 }
.sink { [weak self] destination in
self?.navigateTo(destination)
}
.store(in: &cancellables)
}
}
Swift 5.5 نے ساختی ہم آہنگی متعارف کرائی، جو Combine کے بغیر async/await کے ذریعے موخر نیویگیشن کو لاگو کرنے کی اجازت دیتی ہے۔ ViewModel ایک async فنکشن فراہم کرتی ہے جو ڈیٹا لوڈ کرنے کے بعد روٹ لوٹاتا ہے۔ Coordinator اس فنکشن کو Task میں کال کرتا ہے اور موصولہ روٹ کی بنیاد پر منتقلی انجام دیتا ہے۔
class AuthViewModel: ObservableObject {
func resolveDeeplink(_ url: URL) async -> AppRoute? {
guard let token = await AuthService.shared.getValidToken() else { return .login }
return await DeeplinkRouter.resolve(url, token: token)
}
}
// In Coordinator:
Task {
if let route = await viewModel.resolveDeeplink(url) {
navigateTo(route)
}
}
Deferred Navigation غیر متزامن منظرناموں کی پروسیسنگ کو آسان بناتی ہے لیکن حالت کے انتظام کے لیے ایک نظم و ضبط والے نقطہ نظر کی ضرورت ہوتی ہے۔ آئیے اہم غلطیوں کا جائزہ لیں جو ڈویلپرز موخر نیویگیشن کو لاگو کرتے وقت کرتے ہیں۔
سب سے عام غلطی — روٹ اسکرین کے مکمل طور پر شروع ہونے اور NavController یا Coordinator کے منتقلی کے لیے تیار ہونے سے پہلے موخر نیویگیشن کرنے کی کوشش۔ اینڈرائیڈ میں یہ IllegalStateException کا باعث بنتی ہے، iOS میں — غیر متعینہ UI حالت کا۔ حل — نیویگیشن کو متحرک کرنے سے پہلے یقینی بنائیں کہ جزو کا لائف سائیکل STARTED یا RESUMED حالت میں ہے۔
اگر StateFlow یا Subject پروسیسنگ کے بعد واقعہ صاف نہیں کرتا، تو پچھلی اسکرین پر واپسی پر صارف خود بخود اسی اسکرین پر ری ڈائریکٹ ہو سکتا ہے۔ اینڈرائیڈ میں replay=0 کے ساتھ SharedFlow یا iOS میں پروسیسنگ کے بعد CurrentValueSubject کو nil کے ساتھ استعمال کریں، تاکہ نیویگیشن کا واقعہ صرف ایک بار متحرک ہو۔
ایپلیکیشن میں تمام نیویگیشن کے لیے ایک مرکزی جزو استعمال کریں۔ جب ہر Activity، Fragment یا ViewController کا اپنا نیویگیشن کنٹرولر ہوتا ہے، تو ایپلیکیشن کے مختلف حصوں کے درمیان موخر نیویگیشن افراتفری کا شکار ہو جاتی ہے۔ ایک ہی Coordinator نیویگیشن منظرناموں کی ڈیبگنگ اور جانچ کو آسان بناتا ہے۔
Deferred Navigation براہ راست نیویگیشن کے مقابلے میں جانچنا زیادہ مشکل ہے کیونکہ غیر متزامن آپریشنز ایک وقتی عنصر متعارف کراتے ہیں۔ اینڈرائیڈ میں TestDispatcher (kotlinx-coroutines-test) اور iOS میں XCTestExpectation استعمال کریں تاکہ ڈیٹا لوڈنگ کی نقل کریں اور تصدیق کریں کہ نیویگیشن متوقع روٹ پر عمل کرتی ہے۔ ہر منظر نامے کی علیحدہ جانچ کے لیے اختیار اور ڈیپ لنک سروسز کو موک کریں۔
اکثر پوچھے گئے سوالات
Deferred Navigation ایک موخر منتقلی کا نمونہ ہے جو کسی بھی غیر متزامن منظر نامے میں لاگو کیا جا سکتا ہے۔ ڈیپ لنک موخر نیویگیشن کے لیے ایک ٹریگر ہے، لیکن واحد نہیں۔ تصدیق اور فیچر فلیگ بھی موخر نیویگیشن استعمال کرتے ہیں۔
جی ہاں، زیادہ تر ایپلیکیشنز ہائبرڈ نقطہ نظر استعمال کرتی ہیں۔ پروڈکٹ کی فہرست والی اسکرین (غیر متزامن انحصار کے بغیر) براہ راست نیویگیشن استعمال کر سکتی ہے، جبکہ ڈیٹا لوڈنگ والی تفصیل والی اسکرین — موخر۔ تقسیم ہر مخصوص اسکرین کے آرکیٹیکچر سے طے ہوتی ہے۔
استعمال کریں اینڈرائیڈ میں replay کے بغیر SharedFlow اور iOS میں بفرنگ کے بغیر combineLatest۔ نئے ٹریگر پر پچھلی سبسکرپشنز منسوخ کریں۔ یہ یقینی بناتا ہے کہ صرف تازہ ترین نیویگیشن واقعہ پروسیس ہو۔
جی ہاں، Compose میں موخر نیویگیشن ViewModel کے StateFlow کی سبسکرپشن اور LaunchedEffect میں NavController.navigate کال کے ذریعے لاگو کی جاتی ہے۔ Google موخر منظرناموں کے لیے ایونٹ پر مبنی ماڈل کے ساتھ Navigation Compose استعمال کرنے کی سفارش کرتا ہے۔
موخر کریں نیویگیشن جب تک ایپلیکیشن دوبارہ فعال نہ ہو جائے۔ اینڈرائیڈ میں واقعات کو فلٹر کرنے کے لیے Lifecycle.State.STARTED استعمال کریں۔ iOS میں Combine یا async/await بلاکس میں UIApplication.State چیک کریں۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں