Deferred Navigation — bu kechiktirilgan navigatsiya namunasi bo'lib, unda keyingi ekranga o'tish asinxron amaliyot tugagandan so'ng amalga oshiriladi, foydalanuvchi harakati paytida emas. Android Developers (2024) ma'lumotlariga ko'ra, deferred navigation navigatsiya va ma'lumotlarni yuklash o'rtasidagi poyga holatidan qochishga imkon beradi, shuningdek push-bildirishnomalar va Deeplinkdan o'tishlarni qayta ishlashni soddalashtiradi. Asosiy farq — marshrut barcha kerakli ma'lumotlar mavjud bo'lgandan keyin hisoblanadi.
Asosiy fikrlar
Deferred Navigation — bu arxitektura namunasi bo'lib, unda navigatsiya qarori barcha kerakli ma'lumotlar mavjud bo'lgunga qadar kechiktiriladi. To'g'ridan-to'g'ri o'tishdan farqli o'laroq, foydalanuvchi tugmani bosadi va darhol yangi ekranga o'tadi, deferred navigation hodisa-triggerni va haqiqiy o'tishni ajratadi, ular orasiga asinxron amaliyot qo'shadi.
Arxitektura nuqtai nazaridan, Deferred Navigation holat o'zgarishiga asoslanadi: tugmani bosish asinxron jarayonni boshlaydi va uning natijasiga obuna bo'lish navigatsiyani ishga tushiradi. Bu, ayniqsa, MVVM yoki MVI arxitekturasiga ega ilovalarda muhim, bunda ViewModel holatni boshqaradi, View (Activity, Fragment, SwiftUI View) esa o'zgarishlarga obuna bo'ladi va o'tish bilan reaksiya beradi. Bunday yondashuv UI va navigatsiya mantig'i o'rtasidagi to'g'ridan-to'g'ri bog'liqlikni yo'q qiladi.
Google I/O 2023 ma'lumotlariga ko'ra, deferred navigation tarmoq so'rovi natijasiga, avtorizatsiya tekshiruviga, konfiguratsiyani yuklashga yoki ruxsatnomalarga bog'liq bo'lgan barcha stsenariylar uchun tavsiya etiladi. Ushbu namuna, shuningdek, Deeplinkni qayta ishlashda majburiydir, bunda ilova avval ishga tushishi, ildiz ekranini yuklashi va keyin maqsadli marshrutga o'tishi kerak.
Deferred Navigation to'g'ridan-to'g'ri o'tish ekranning noto'g'ri holatiga yoki yuklash xatolariga olib keladigan stsenariylarda qo'llaniladi. Kechiktirilgan navigatsiya majburiy bo'lgan to'rtta asosiy holatni ko'rib chiqamiz.
Agar foydalanuvchi himoyalangan kontentni bossa, ilova avval kirish tokenini tekshirishi kerak. To'g'ridan-to'g'ri navigatsiya kontent ekraniga token muddati tugagan bo'lsa, bo'sh ekran yoki 401 xatosiga olib keladi. Deferred navigation tokenni tekshiradi va faqat muvaffaqiyatli bo'lganda maqsadli ekranga o'tadi. Muvaffaqiyatsizlikda kirish ekraniga yo'naltiradi.
Ilova tashqi havola orqali ochilganda, avval ildiz ekranini yuklash, navigatsiya holatini tiklash va keyin Deeplink orqali o'tishni amalga oshirish kerak. Ildiz kontekstisiz maqsadli ekranga to'g'ridan-to'g'ri navigatsiya anomaliyalarga olib keladi: bo'sh navigatsiya steki yoki buzilgan back stack.
Push-bildirishnomani bosganda ilova uch holatda bo'lishi mumkin: yopiq, fonda yoki faol. Deferred Navigation ilova holatini aniqlaydi, kerakli kontentni yuklaydi va keyin maqsadli ekranni ko'rsatadi. iOS UNNotificationContentExtension orqali ushbu stsenariyni qayta ishlashga imkon beradi.
Ekran funksionalligi serverdagi feature flag bilan boshqarilsa, deferred navigation avval konfiguratsiyani so'rashga va keyin ekranni ko'rsatishga imkon beradi. Agar funksiya o'chirilgan bo'lsa, foydalanuvchi bo'sh ekran o'rniga muqobil kontent yoki placeholder ko'radi.
| Stsenariy | To'g'ridan-to'g'ri navigatsiya | Deferred Navigation |
|---|---|---|
| Avtorizatsiya | Token muddati tugaganda bo'sh ekran | Kirishga yo'naltirish |
| Deeplink | Buzilgan back stack | To'g'ri navigatsiya steki |
| Push | Kontekstsiz yuklash | Ma'lumotlar o'tishdan oldin tayyor |
| Feature flag | Mavjud bo'lmagan funksiyani ko'rsatish | Placeholder yoki muqobil |
To'g'ridan-to'g'ri navigatsiya (direct navigation) — an'anaviy yondashuv bo'lib, unda o'tish hodisaga javoban darhol amalga oshiriladi. Foydalanuvchi tugmani bosadi va UI marshrutizatori darhol ekranni o'zgartiradi. Bu yondashuv sodda va bashorat qilinadigan, ammo server ma'lumotlari yoki shartlarni tekshirish kerak bo'lgan stsenariylarda cheklangan.
Deferred Navigation asinxron holat ko'rinishida qatlam qo'shadi. Foydalanuvchi hodisasi operatsiyani boshlaydi va natijaga obuna bo'lish navigatsiyani boshqaradi. Bu kod murakkabligini oshiradi, lekin moslashuvchanlik beradi: bir xil trigger yuklangan ma'lumotlarga qarab turli ekranlarga olib kelishi mumkin.
Ikki yondashuv o'rtasidagi tanlov talablarga bog'liq: agar ekranni ko'rsatish uchun asinxron ma'lumotlar kerak bo'lmasa — to'g'ridan-to'g'ri navigatsiyadan foydalaning. Agar ekran so'rov natijasiga, avtorizatsiyaga yoki tashqi shartlarga bog'liq bo'lsa — deferred navigation majburiydir. Gibrid yondashuv, o'tishlarning bir qismi to'g'ridan-to'g'ri va bir qismi kechiktirilgan — ishlab chiqarish ilovalarida eng keng tarqalgan amaliyotdir.
Android Jetpack Deferred Navigation-ni arxitektura darajasida amalga oshirish mexanizmlarini taqdim etadi. Asosiy g'oya — ViewModel holatni boshqaradi, Activity yoki Fragment esa o'zgarishlarga obuna bo'ladi va NavController orqali navigatsiyani ishga tushiradi.
StateFlow Kotlin coroutines-da deferred navigation uchun ideal vositadir. ViewModel StateFlow-ni navigatsiya hodisasi bilan yangilaydi, Activity esa uni kuzatadi va o'tishni amalga oshiradi. Hodisa qayta ishlanganda StateFlow tozalanadi, qayta navigatsiyaning oldini oladi.
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 da navigatsiyaga obuna bo'lish ViewModel-dan marshrut bilan NavController-ni ishga tushiradi. Ekran aylanishida qayta navigatsiyaning oldini olish uchun NavigationEventWrapper ishlatiladi, u hodisani faqat bir marta qayta ishlaydi. Jetpack Navigation 2.7+ argumentlarni xavfsiz uzatish uchun Safe Args-ni qo'llab-quvvatlaydi.
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-ga o'xshash o'rnatilgan Navigation Component-ga ega emas, shuning uchun dasturchilar Deferred Navigation-ni Coordinator Pattern orqali Combine yoki async/await bilan birgalikda amalga oshiradilar. Coordinator ekranlar to'plamini boshqaradi va yuklangan ma'lumotlar asosida navigatsiya qarorlarini qabul qiladi.
Coordinator — ViewController-lar o'rtasida navigatsiyani boshqaradigan ob'ekt. Combine bilan birgalikda ViewModel hodisalarni PassthroughSubject orqali nashr etadi, Coordinator esa ularga obuna bo'ladi va o'tishni amalga oshiradi. Bunday yondashuv UI-ni navigatsiya mantig'idan butunlay ajratadi va Apple-ning ilova arxitekturasi bo'yicha tavsiyalariga mos keladi.
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 structured concurrency-ni taqdim etdi, bu Combine-siz async/await orqali kechiktirilgan navigatsiyani amalga oshirishga imkon beradi. ViewModel ma'lumotlarni yuklagandan so'ng marshrutni qaytaruvchi async-funksiyani taqdim etadi. Coordinator bu funksiyani Task-da chaqiradi va olingan marshrut bo'yicha o'tishni amalga oshiradi.
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)
}
}
// Coordinator-da:
Task {
if let route = await viewModel.resolveDeeplink(url) {
navigateTo(route)
}
}
Deferred Navigation asinxron stsenariylarni qayta ishlashni soddalashtiradi, lekin holatni boshqarishga intizomli yondashishni talab qiladi. Deferred navigation-ni joriy etishda dasturchilar yo'l qo'yadigan asosiy xatolarni ko'rib chiqamiz.
Eng keng tarqalgan xato — ildiz ekran to'liq initsializatsiya qilinmagan va NavController yoki Coordinator o'tishga tayyor bo'lmaganida deferred navigation amalga oshirishga urinish. Android-da bu IllegalStateException-ga, iOS-da esa noaniq UI holatiga olib keladi. Yechim — navigatsiyani boshlashdan oldin komponentning hayot aylanishi STARTED yoki RESUMED holatida ekanligiga ishonch hosil qiling.
Agar StateFlow yoki Subject hodisani qayta ishlashdan keyin tozalamasa, oldingi ekranga qaytganda foydalanuvchi avtomatik ravishda yana o'sha ekranga yo'naltirilishi mumkin. Android-da replay=0 bo'lgan SharedFlow yoki iOS-da qayta ishlashdan keyin nil bo'lgan CurrentValueSubject dan foydalaning, navigatsiya hodisasi faqat bir marta ishga tushsin.
Ilovadagi barcha navigatsiya uchun bitta markaziy komponentdan foydalaning. Har bir Activity, Fragment yoki ViewController o'z navigatsiya boshqaruvchisiga ega bo'lsa, ilovaning turli qismlari o'rtasida deferred navigation tartibsiz bo'ladi. Yagona Coordinator navigatsiya stsenariylarini disk raskadrovka qilish va test qilishni osonlashtiradi.
Deferred Navigation to'g'ridan-to'g'ri navigatsiyadan ko'ra test qilish qiyinroq, chunki asinxron operatsiyalar vaqt omilini keltiradi. Android-da TestDispatcher (kotlinx-coroutines-test) va iOS-da XCTestExpectation dan foydalanib ma'lumotlarni yuklashni simulyatsiya qiling va navigatsiya kutilgan marshrut bo'ylab amalga oshirilayotganini tekshiring. Har bir stsenariyni izolyatsiya qilingan holda testlash uchun avtorizatsiya va deeplink xizmatlarini mock qiling.
Tez-tez beriladigan savollar
Deferred Navigation — kechiktirilgan o'tish namunasi bo'lib, har qanday asinxron stsenariyda qo'llanilishi mumkin. Deep Link deferred navigation uchun triggerlardan biridir, ammo yagona emas. Avtorizatsiya va feature flaglar ham kechiktirilgan navigatsiyadan foydalanadi.
Ha, ko'pchilik ilovalar gibrid yondashuvdan foydalanadi. Mahsulot ro'yxati ekrani (asinxron bog'liqliklarsiz) to'g'ridan-to'g'ri navigatsiyadan foydalanishi mumkin, ma'lumotlarni yuklash bilan detal ekrani esa deferred. Bo'linish aniq ekran arxitekturasi bilan belgilanadi.
Ishlating Android-da replaysiz SharedFlow va iOS-da buferlashsiz combineLatest. Yangi triggerda oldingi obunalarni bekor qiling. Bu faqat oxirgi navigatsiya hodisasi qayta ishlanishini kafolatlaydi.
Ha, Compose-da deferred navigation ViewModel StateFlow-iga obuna bo'lish va LaunchedEffect ichida NavController.navigate chaqirish orqali amalga oshiriladi. Google deferred stsenariylar uchun Navigation Compose-ni hodisa modeli bilan ishlatishni tavsiya qiladi.
Kechiktiring navigatsiyani ilova yana faol bo'lgunga qadar. Android-da hodisalarni filtrlash uchun Lifecycle.State.STARTED dan foydalaning. iOS-da Combine yoki async/await blokida UIApplication.State ni tekshiring.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.