Deferred Navigation — gecikmiş naviqasiya nümunəsidir, burada növbəti ekrana keçid asinxron əməliyyat tamamlandıqdan sonra baş verir, istifadəçinin hərəkəti anında deyil. Android Developers (2024)-ə görə, deferred navigation naviqasiya və məlumat yükləmə arasında yarış vəziyyətindən qaçmağa imkan verir, həmçinin push bildirişləri və Deeplink-dən keçidlərin işlənməsini sadələşdirir. Əsas fərq — marşrut bütün lazımi məlumatlar əldə edildikdən sonra hesablanır.
Əsas məqamlar
Deferred Navigation — memarlıq nümunəsidir, burada naviqasiya qərarı bütün lazımi məlumatlar əldə olunana qədər təxirə salınır. Birbaşa keçiddən fərqli olaraq, istifadəçi düyməni basır və dərhal yeni ekrana düşür, deferred navigation trigger-hadisəni və faktiki keçidi ayırır, aralarında asinxron əməliyyat əlavə edir.
Memarlıq baxımından Deferred Navigation vəziyyət dəyişikliyinə əsaslanır: düymənin basılması asinxron prosesi başladır, nəticəyə abunəlik isə naviqasiyanı işə salır. Bu, xüsusilə MVVM və ya MVI arxitekturası olan proqramlarda vacibdir, burada ViewModel vəziyyəti idarə edir, View (Activity, Fragment, SwiftUI View) isə dəyişikliklərə abunə olur və keçidlə reaksiya verir. Bu yanaşma UI ilə naviqasiya məntiqi arasında birbaşa asılılığı aradan qaldırır.
Google I/O 2023 məlumatlarına görə, deferred navigation şəbəkə sorğusunun nəticəsindən, avtorizasiya yoxlanışından, konfiqurasiya yükləməsindən və ya icazələrdən asılı olan bütün ssenarilər üçün tövsiyə olunur. Bu nümunə həmçinin Deeplink-in işlənməsi zamanı məcburidir, proqram əvvəlcə işə düşməli, kök ekranı yükləməli və yalnız bundan sonra hədəf marşruta keçməlidir.
Deferred Navigation birbaşa keçidin ekranın səhv vəziyyətinə və ya yükləmə xətalarına səbəb olduğu ssenarilərdə tətbiq olunur. Gecikmiş naviqasiyanın məcburi olduğu dörd əsas halı nəzərdən keçirək.
İstifadəçi qorunan məzmuna klik edərsə, proqram əvvəlcə giriş tokenini yoxlamalıdır. Birbaşa naviqasiya məzmun ekranına tokenin müddəti bitibsə boş ekrana və ya 401 xətasına səbəb olacaq. Deferred navigation tokeni yoxlayır və yalnız uğur olduqda — hədəf ekrana keçir. Uğursuzluq halında — giriş ekranına yönləndirir.
Proqram xarici keçid vasitəsilə açıldıqda, əvvəlcə kök ekranı yükləmək, naviqasiya vəziyyətini bərpa etmək və yalnız sonra Deeplink üzrə keçidi yerinə yetirmək lazımdır. Kök konteksti olmadan hədəf ekrana birbaşa naviqasiya anomaliyalara səbəb olacaq: boş naviqasiya yığını və ya sınmış back stack.
Push bildirişinə toxunduqda proqram üç vəziyyətdə ola bilər: bağlı, fon və ya aktiv. Deferred Navigation proqramın vəziyyətini müəyyən edir, lazımi məzmunu yükləyir və yalnız sonra hədəf ekranı göstərir. iOS bu ssenarini UNNotificationContentExtension vasitəsilə idarə etməyə imkan verir.
Ekranın funksionallığı serverdən feature flag ilə idarə olunursa, deferred navigation əvvəlcə konfiqurasiyanı sorğulamağa və yalnız sonra ekranı göstərməyə imkan verir. Funksiya söndürülübsə — istifadəçi boş ekran əvəzinə alternativ məzmun və ya placeholder görür.
| Ssenari | Birbaşa naviqasiya | Deferred Navigation |
|---|---|---|
| Avtorizasiya | Token müddəti bitdikdə boş ekran | Giriş səhifəsinə yönləndirmə |
| Deeplink | Back stack sınması | Düzgün naviqasiya yığını |
| Push | Kontekstsiz yükləmə | Məlumat keçiddən əvvəl hazırdır |
| Feature flag | Əlçatmaz funksiyanın göstərilməsi | Placeholder və ya alternativ |
Birbaşa naviqasiya (direct navigation) — ənənəvi yanaşma, burada keçid hadisəyə cavab olaraq dərhal icra olunur. İstifadəçi düyməni basır və UI router dərhal ekranı dəyişir. Bu yanaşma sadə və proqnozlaşdırıla biləndir, lakin server məlumatları və ya şərtlərin yoxlanılması tələb olunan ssenarilərdə məhduddur.
Deferred Navigation asinxron vəziyyət şəklində bir təbəqə əlavə edir. İstifadəçinin hadisəsi əməliyyatı başladır, nəticəyə abunəlik isə naviqasiyanı idarə edir. Bu kodun mürəkkəbliyini artırır, lakin çeviklik verir: eyni trigger yüklənmiş məlumatlardan asılı olaraq müxtəlif ekranlara apara bilər.
İki yanaşma arasında seçim tələblərdən asılıdır: ekranın göstərilməsi üçün asinxron məlumat tələb olunmursa — birbaşa naviqasiyadan istifadə edin. Ekran sorğunun nəticəsindən, avtorizasiyadan və ya xarici şərtlərdən asılıdırsa — deferred navigation məcburidir. Hibrid yanaşma, keçidlərin bir hissəsinin birbaşa, bir hissəsinin isə gecikmiş olduğu — istehsalat proqramlarında ən geniş yayılmış təcrübədir.
Android Jetpack Deferred Navigation-ın memarlıq səviyyəsində tətbiqi üçün mexanizmlər təqdim edir. Əsas ideya — ViewModel vəziyyəti idarə edir, Activity və ya Fragment isə dəyişikliklərə abunə olur və NavController vasitəsilə naviqasiyanı işə salır.
StateFlow Kotlin coroutines-də deferred navigation üçün ideal alətdir. ViewModel naviqasiya hadisəsi ilə StateFlow-u yeniləyir, Activity isə onu müşahidə edir və keçidi yerinə yetirir. Hadisə işləndikdə StateFlow təmizlənir, təkrar naviqasiyanın qarşısını alır.
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-də naviqasiyaya abunəlik ViewModel-dən marşrutla NavController-ı işə salır. Ekran fırlanması zamanı təkrar naviqasiyanın qarşısını almaq üçün NavigationEventWrapper istifadə olunur, hadisəni yalnız bir dəfə işləyir. Jetpack Navigation 2.7+ arqumentlərin tip-təhlükəsiz ötürülməsi üçün Safe Args-ı dəstəkləyir.
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-da Android Jetpack-ə bənzər daxili Navigation Component yoxdur, buna görə tərtibatçılar Deferred Navigation-ı Coordinator Pattern vasitəsilə Combine və ya async/await ilə birlikdə həyata keçirirlər. Coordinator ekran yığınını idarə edir və yüklənmiş məlumatlar əsasında naviqasiya qərarları qəbul edir.
Coordinator — ViewController-lar arasında naviqasiyanı idarə edən obyekt. Combine ilə birlikdə ViewModel hadisələri PassthroughSubject vasitəsilə yayımlayır, Coordinator isə onlara abunə olur və keçidi yerinə yetirir. Bu yanaşma UI-nı naviqasiya məntiqindən tamamilə ayırır və Apple-ın proqram arxitekturası üzrə tövsiyələrinə uyğundur.
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 təqdim etdi ki, bu da Combine olmadan async/await vasitəsilə gecikmiş naviqasiyanı həyata keçirməyə imkan verir. ViewModel məlumat yükləndikdən sonra marşrutu qaytaran async-funksiya təqdim edir. Coordinator bu funksiyanı Task-da çağırır və alınan marşrut üzrə keçidi yerinə yetirir.
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 ssenarilərin işlənməsini sadələşdirir, lakin vəziyyətin idarə edilməsinə intizamlı yanaşma tələb edir. Deferred navigation tətbiq edərkən tərtibatçıların buraxdığı əsas səhvləri nəzərdən keçirək.
Ən çox yayılmış səhv — kök ekran tam inisializasiya olunmamış və NavController və ya Coordinator keçidə hazır olmamış deferred navigation etməyə cəhd etməkdir. Android-də bu IllegalStateException-a, iOS-da — qeyri-müəyyən UI vəziyyətinə səbəb olur. Həll yolu — naviqasiyanı işə salmazdan əvvəl komponentin həyat dövrünün STARTED və ya RESUMED vəziyyətində olduğundan əmin olun.
Əgər StateFlow və ya Subject hadisəni işləndikdən sonra təmizləmirsə, əvvəlki ekrana qayıtdıqda istifadəçi avtomatik olaraq eyni ekrana yenidən yönləndirilə bilər. Android-də replay=0 olan SharedFlow və ya iOS-da işlənmədən sonra nil olan CurrentValueSubject istifadə edin ki, naviqasiya hadisəsi yalnız bir dəfə işləsin.
Proqramda bütün naviqasiya üçün bir mərkəzi komponentdən istifadə edin. Hər Activity, Fragment və ya ViewController-in öz naviqasiya kontrolleri olduqda, proqramın müxtəlif hissələri arasında deferred navigation xaotik olur. Vahid Coordinator naviqasiya ssenarilərinin debug və testini asanlaşdırır.
Deferred Navigation birbaşa naviqasiyadan daha çətin test olunur, çünki asinxron əməliyyatlar zaman faktoru gətirir. Android-də TestDispatcher (kotlinx-coroutines-test) və iOS-da XCTestExpectation istifadə edərək məlumat yükləməsini simulyasiya edin və naviqasiyanın gözlənilən marşrut üzrə icra olunduğunu yoxlayın. Hər ssenarinin izolyasiya olunmuş testi üçün avtorizasiya və deeplink xidmətlərini mock edin.
Tez-tez verilən suallar
Deferred Navigation — gecikmiş keçid nümunəsidir, istənilən asinxron ssenaridə tətbiq oluna bilər. Deep Link deferred navigation üçün triggerlərdən biridir, lakin yeganə deyil. Avtorizasiya və feature flaglar da gecikmiş naviqasiyadan istifadə edir.
Bəli, əksər proqramlar hibrid yanaşmadan istifadə edir. Məhsul siyahısı ekranı (asinxron asılılıqlar olmadan) birbaşa naviqasiyadan istifadə edə bilər, məlumat yükləməsi olan detal ekranı isə deferred. Bölgü konkret ekranın arxitekturası ilə müəyyən edilir.
İstifadə edin Android-də replay olmadan SharedFlow və iOS-da bufferləşdirməsiz combineLatest. Yeni trigger olduqda əvvəlki abunəlikləri ləğv edin. Bu, yalnız son naviqasiya hadisəsinin işlənməsini təmin edir.
Bəli, Compose-da deferred navigation ViewModel-in StateFlow-na abunəlik və LaunchedEffect-də NavController.navigate çağırışı ilə həyata keçirilir. Google deferred ssenarilər üçün Navigation Compose-dan hadisə modeli ilə istifadə etməyi tövsiyə edir.
Təxirə salın naviqasiyanı proqram yenidən aktiv olana qədər. Android-də hadisələri filtrləmək üçün Lifecycle.State.STARTED istifadə edin. iOS-da Combine və ya async/await blokunda UIApplication.State-i yoxlayın.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun