Deferred Navigation (Ertelenmiş Navigasyon), bir sonraki ekrana geçişin asenkron bir işlem tamamlandıktan sonra gerçekleştiği, kullanıcı eylemi anında doğrudan olmayan bir navigasyon modelidir. Android Developers (2024)'e göre, ertelenmiş navigasyon, navigasyon ve veri yükleme arasındaki yarış durumlarını önlemeye yardımcı olur ve push bildirimleri ile Deeplink'lerden geçişlerin işlenmesini basitleştirir. Temel fark — rota, gerekli tüm veriler kullanılabilir olduktan sonra hesaplanır.
Önemli Noktalar
Deferred Navigation (Ertelenmiş Navigasyon), gerekli tüm veriler kullanılabilir olana kadar navigasyon kararının ertelendiği bir mimari modeldir. Kullanıcının bir düğmeye basıp hemen yeni bir ekrana ulaştığı doğrudan geçişin aksine, ertelenmiş navigasyon tetikleyici olay ile gerçek geçişi ayırır ve aralarına asenkron bir işlem yerleştirir.
Mimari olarak, Deferred Navigation durum değişikliği üzerine kuruludur: bir düğmeye basmak asenkron bir süreci başlatır ve sonucuna abone olmak navigasyonu tetikler. Bu, MVVM veya MVI mimarisine sahip uygulamalarda özellikle önemlidir; burada ViewModel durumu yönetir ve View (Activity, Fragment, SwiftUI View) değişikliklere abone olur ve bir geçişle yanıt verir. Bu yaklaşım, UI ile navigasyon mantığı arasındaki doğrudan bağımlılığı ortadan kaldırır.
Google I/O 2023'e göre, ertelenmiş navigasyon, navigasyonun bir ağ isteğinin sonucuna, kimlik doğrulama kontrolüne, yapılandırma yüklemeye veya izinlere bağlı olduğu tüm senaryolar için önerilir. Model ayrıca Deeplink'leri işlerken de zorunludur; uygulamanın önce başlatılması, kök ekranı yüklemesi ve ancak bundan sonra hedef rotaya gitmesi gerekir.
Deferred Navigation, doğrudan navigasyonun yanlış ekran durumuna veya yükleme hatalarına yol açtığı senaryolarda kullanılır. Ertelenmiş navigasyonun gerekli olduğu dört ana durumu inceleyelim.
Bir kullanıcı korunan içeriğe dokunursa, uygulamanın önce erişim token'ını kontrol etmesi gerekir. Token'ın süresi dolmuşsa, içerik ekranına doğrudan navigasyon boş bir ekrana veya 401 hatasına yol açar. Ertelenmiş navigasyon token'ı kontrol eder ve yalnızca başarılı olursa — hedef ekrana gider. Başarısızlık durumunda — giriş ekranına yönlendirir.
Bir uygulama harici bir bağlantı yoluyla açıldığında, önce kök ekranı yüklemeli, navigasyon durumunu geri yüklemeli ve ancak bundan sonra Deeplink geçişini gerçekleştirmelidir. Kök bağlam olmadan hedef ekrana doğrudan navigasyon, anormalliklere yol açar: boş bir navigasyon yığını veya bozuk bir geri yığını.
Bir push bildirimine dokunulduğunda, uygulama üç durumdan birinde olabilir: kapalı, arka planda veya aktif. Deferred Navigation, uygulamanın durumunu belirler, gerekli içeriği yükler ve ancak bundan sonra hedef ekranı gösterir. iOS, bu senaryonun UNNotificationContentExtension aracılığıyla işlenmesine izin verir.
Bir ekranın işlevselliği sunucudan gelen bir özellik bayrağı tarafından kontrol ediliyorsa, ertelenmiş navigasyon önce yapılandırmayı talep etmeye ve ancak bundan sonra ekranı göstermeye izin verir. Özellik devre dışıysa — kullanıcı boş bir ekran yerine alternatif içerik veya bir yer tutucu görür.
| Senaryo | Doğrudan navigasyon | Deferred Navigation |
|---|---|---|
| Yetkilendirme | Süresi dolmuş token ile boş ekran | Girişe yönlendirme |
| Deeplink | Bozuk geri yığını | Doğru navigasyon yığını |
| Push | Bağlamsız yükleme | Geçişten önce veriler hazır |
| Özellik bayrağı | Kullanılamayan işlevi gösterme | Yer tutucu veya alternatif |
Doğrudan navigasyon, bir olaya yanıt olarak geçişin hemen gerçekleştirildiği geleneksel bir yaklaşımdır. Kullanıcı bir düğmeye basar ve UI yönlendiricisi hemen ekranı değiştirir. Bu yaklaşım basit ve öngörülebilirdir ancak sunucudan veri veya koşul kontrolleri gerektiren senaryolarda sınırlıdır.
Deferred Navigation, asenkron durum biçiminde bir katman ekler. Bir kullanıcı olayı bir işlemi başlatır ve sonucuna abone olmak navigasyonu kontrol eder. Bu, kod karmaşıklığını artırır ancak esneklik sağlar: aynı tetikleyici, yüklenen verilere bağlı olarak farklı ekranlara yol açabilir.
İki yaklaşım arasındaki seçim gereksinimlere bağlıdır: bir ekranı görüntülemek asenkron veri gerektirmiyorsa — doğrudan navigasyon kullanın. Ekran bir isteğin, yetkilendirmenin veya dış koşulların sonucuna bağlıysa — ertelenmiş navigasyon gereklidir. Bazı geçişlerin doğrudan, bazılarının ertelenmiş olduğu hibrit bir yaklaşım, endüstriyel uygulamalarda en yaygın uygulamadır.
Android Jetpack, mimari düzeyde Deferred Navigation uygulamak için mekanizmalar sağlar. Temel fikir — ViewModel durumu yönetirken, Activity veya Fragment değişikliklere abone olur ve NavController aracılığıyla navigasyonu tetikler.
StateFlow Kotlin coroutine'lerinde ertelenmiş navigasyon için ideal araçtır. ViewModel, bir navigasyon olayıyla StateFlow'u günceller ve Activity onu gözlemler ve geçişi gerçekleştirir. Olay işlendiğinde, StateFlow temizlenir ve tekrarlanan navigasyon önlenir.
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'de, navigasyona abonelik, ViewModel'den gelen rota ile NavController'ı tetikler. Ekran döndürmede tekrarlanan navigasyonu önlemek için, olayı yalnızca bir kez işleyen bir NavigationEventWrapper sarmalayıcısı kullanılır. Jetpack Navigation 2.7+, tür güvenli argüman geçişi için Safe Args'yi destekler.
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'e benzer yerleşik bir Navigation Component'e sahip değildir, bu nedenle geliştiriciler Deferred Navigation'ı Combine veya async/await ile birlikte Coordinator Pattern aracılığıyla uygular. Coordinator, ekran yığınını yönetir ve yüklenen verilere dayalı olarak navigasyon kararları alır.
Coordinator, ViewController'lar arasındaki navigasyonu yöneten bir nesnedir. Combine ile birlikte, ViewModel olayları PassthroughSubject aracılığıyla yayınlar ve Coordinator bunlara abone olur ve geçişi gerçekleştirir. Bu yaklaşım, UI'yı navigasyon mantığından tamamen ayırır ve Apple'ın uygulama mimarisi önerilerini takip eder.
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 olmadan async/await aracılığıyla ertelenmiş navigasyon uygulamaya izin veren yapılandırılmış eşzamanlılığı tanıttı. ViewModel, verileri yükledikten sonra bir rota döndüren bir async işlevi sağlar. Coordinator, bu işlevi bir Task içinde çağırır ve alınan rotaya dayalı olarak geçişi gerçekleştirir.
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 asenkron senaryoların işlenmesini basitleştirir ancak durum yönetimine disiplinli bir yaklaşım gerektirir. Geliştiricilerin ertelenmiş navigasyonu uygularken yaptığı ana hataları inceleyelim.
En yaygın hata — kök ekran tamamen başlatılmadan ve NavController veya Coordinator geçişe hazır olmadan önce ertelenmiş navigasyon gerçekleştirmeye çalışmak. Android'de bu IllegalStateException'a, iOS'te — tanımsız bir UI durumuna yol açar. Çözüm — navigasyonu tetiklemeden önce bileşenin yaşam döngüsünün STARTED veya RESUMED durumunda olduğundan emin olmaktır.
StateFlow veya Subject işlemeden sonra olayı temizlemezse, önceki ekrana dönerken kullanıcı otomatik olarak aynı ekrana yönlendirilebilir. Android'de replay=0 ile SharedFlow veya iOS'te işlemeden sonra CurrentValueSubject'i nil ile kullanın, böylece navigasyon olayı yalnızca bir kez tetiklenir.
Uygulamadaki tüm navigasyon için tek bir merkezi bileşen kullanın. Her Activity, Fragment veya ViewController'ın kendi navigasyon denetleyicisi olduğunda, uygulamanın farklı bölümleri arasındaki ertelenmiş navigasyon kaotik hale gelir. Tek bir Coordinator, navigasyon senaryolarının hata ayıklamasını ve test edilmesini basitleştirir.
Deferred Navigation, doğrudan navigasyondan daha zor test edilir çünkü asenkron işlemler bir zaman faktörü ekler. Veri yüklemeyi simüle etmek ve navigasyonun beklenen rotayı izlediğini doğrulamak için Android'de TestDispatcher (kotlinx-coroutines-test) ve iOS'te XCTestExpectation kullanın. Her senaryonun izole testi için yetkilendirme ve deeplink hizmetlerini taklit edin.
Sıkça Sorulan Sorular
Deferred Navigation, herhangi bir asenkron senaryoda uygulanabilen ertelenmiş geçiş modelidir. Deep Link, ertelenmiş navigasyon için bir tetikleyicidir, ancak tek değildir. Kimlik doğrulama ve özellik bayrakları da ertelenmiş navigasyon kullanır.
Evet, çoğu uygulama hibrit bir yaklaşım kullanır. Asenkron bağımlılıkları olmayan bir ürün listesi ekranı doğrudan navigasyon kullanabilirken, veri yüklemeli bir detay ekranı ertelenmiş kullanır. Ayrım, her bir belirli ekranın mimarisine göre belirlenir.
Kullanın Android'de replay olmadan SharedFlow ve iOS'te tamponlama olmadan combineLatest. Yeni bir tetikleyicide önceki abonelikleri iptal edin. Bu, yalnızca en son navigasyon olayının işlenmesini sağlar.
Evet, Compose'da ertelenmiş navigasyon, ViewModel StateFlow'una abonelik ve LaunchedEffect içinde NavController.navigate çağrısı yoluyla uygulanır. Google, ertelenmiş senaryolar için olay odaklı modelle Navigation Compose kullanılmasını önerir.
Erteleyin uygulama tekrar aktif olana kadar navigasyonu. Android'de olayları filtrelemek için Lifecycle.State.STARTED kullanın. iOS'te Combine veya async/await bloklarında UIApplication.State'i kontrol edin.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun