Gezinme bileşeni, belirli gezinme öğelerini programatik olarak oluşturmak ve bunlarla etkileşimde bulunmak için yöntemler sağlar.
NavHostFragment oluşturma
Aşağıdaki örnekte gösterildiği gibi, belirli bir grafik kaynağıyla programatik bir şekilde NavHostFragment
oluşturmak için NavHostFragment.create()
kullanabilirsiniz:
Kotlin
val finalHost = NavHostFragment.create(R.navigation.example_graph) supportFragmentManager.beginTransaction() .replace(R.id.nav_host, finalHost) .setPrimaryNavigationFragment(finalHost) // equivalent to app:defaultNavHost="true" .commit()
Java
NavHostFragment finalHost = NavHostFragment.create(R.navigation.example_graph); getSupportFragmentManager().beginTransaction() .replace(R.id.nav_host, finalHost) .setPrimaryNavigationFragment(finalHost) // equivalent to app:defaultNavHost="true" .commit();
setPrimaryNavigationFragment(finalHost)
işlevinin NavHost
sisteminizin Geri düğmesine basmasını engellediğini unutmayın. Bu davranışı app:defaultNavHost="true"
ekleyerek NavHost
XML'nizde de uygulayabilirsiniz. Özel Geri düğmesi davranışını uyguluyor ve NavHost
öğesinin Geri düğmesine basılmasını engellemek istemiyorsanız null
politikasını setPrimaryNavigationFragment()
değerine geçirebilirsiniz.
NavBackStackEntry kullanarak bir hedefe referans verme
Gezinme 2.2.0'dan başlayarak, gezinme yığınındaki herhangi bir hedefe ilişkin NavBackStackEntry
referansını, NavController.getBackStackEntry()
çağrısı yaparak ve bu hedefe bir hedef kimliği ileterek alabilirsiniz. Arka yığın, belirtilen hedefin birden fazla örneğini içeriyorsa getBackStackEntry()
, yığındaki en üst örneği döndürür.
Döndürülen NavBackStackEntry
, hedef düzeyinde bir Lifecycle
, ViewModelStore
ve SavedStateRegistry
sağlar. Bu nesneler, arka yığındaki hedefin kullanım ömrü boyunca geçerlidir. İlişkili hedef arka yığından çıkarıldığında Lifecycle
yok edilir, durum artık kaydedilmez ve tüm ViewModel
nesneleri temizlenir.
Bu özellikler, ne tür bir hedef kullanırsanız kullanın size kaydedilmiş durum ile çalışan ViewModel
nesne ve sınıfları için bir Lifecycle
ve depolama alanı sağlar. Bu, özellikle özel hedefler gibi otomatik olarak ilişkili bir Lifecycle
içermeyen hedef türleriyle çalışırken kullanışlıdır.
Örneğin, bir NavBackStackEntry
öğesinin Lifecycle
özelliğini, bir parçanın veya etkinliğin Lifecycle
özelliğini gözlemlediğiniz gibi gözlemleyebilirsiniz. Ayrıca NavBackStackEntry
bir LifecycleOwner
olduğundan aşağıdaki örnekte gösterildiği gibi LiveData
öğesini gözlemlerken veya yaşam döngüsüne duyarlı diğer bileşenlerle birlikte kullanabilirsiniz:
Kotlin
myViewModel.liveData.observe(backStackEntry, Observer { myData -> // react to live data update })
Java
myViewModel.getLiveData().observe(backStackEntry, myData -> { // react to live data update });
navigate()
numaralı telefonu her aradığınızda yaşam döngüsü durumu otomatik olarak güncellenir.
Geri yığının en üstünde olmayan hedefler için yaşam döngüsü durumları, hedefler iletişim kutusu hedefi gibi bir FloatingWindow
hedefi altında hâlâ görünür durumdaysa RESUMED
konumundan STARTED
konumuna, aksi takdirde STOPPED
konumuna taşınır.
Bir sonucu önceki Hedefe döndürme
Navigasyon 2.3 ve sonraki sürümlerde NavBackStackEntry
, bir
SavedStateHandle
öğesine erişim izni verir.
SavedStateHandle
, verileri depolamak ve almak için kullanılabilecek bir anahtar/değer eşlemesidir. Bu değerler, yapılandırma değişiklikleri de dahil olmak üzere işlemin tamamlanmasına kadar devam eder ve aynı nesne üzerinden kullanılabilir durumda kalır. Belirtilen SavedStateHandle
sayesinde verilere erişebilir ve hedefler arasında veri aktarabilirsiniz.
Bu, özellikle verileri bir hedef yığından kaldırıldıktan sonra geri alma mekanizması olarak yararlıdır.
Verileri Hedef B'den A Hedefine geri iletmek için önce A Hedefi'ni SavedStateHandle
üzerinden bir sonucu dinleyecek şekilde ayarlayın.
Bunu yapmak için getCurrentBackStackEntry()
API'yı ve ardından SavedStateHandle
tarafından sağlanan observe
LiveData
öğesini kullanarak NavBackStackEntry
alın.
Kotlin
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val navController = findNavController(); // We use a String here, but any type that can be put in a Bundle is supported navController.currentBackStackEntry?.savedStateHandle?.getLiveData<String>("key")?.observe( viewLifecycleOwner) { result -> // Do something with the result. } }
Java
@Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { NavController navController = NavHostFragment.findNavController(this); // We use a String here, but any type that can be put in a Bundle is supported MutableLiveData<String> liveData = navController.getCurrentBackStackEntry() .getSavedStateHandle() .getLiveData("key"); liveData.observe(getViewLifecycleOwner(), new Observer<String>() { @Override public void onChanged(String s) { // Do something with the result. } }); }
Hedef B'de, getPreviousBackStackEntry()
API'yi kullanarak A Hedefi'nin SavedStateHandle
sonucu için set
gerekir.
Kotlin
navController.previousBackStackEntry?.savedStateHandle?.set("key", result)
Java
navController.getPreviousBackStackEntry().getSavedStateHandle().set("key", result);
Bir sonucu yalnızca bir kez işlemek isterseniz sonucu temizlemek için SavedStateHandle
üzerinde remove()
işlevini çağırmanız gerekir. Sonucu kaldırmazsanız LiveData
, son sonucu yeni Observer
örneklerine döndürmeye devam eder.
İletişim kutusu hedeflerini kullanırken dikkat edilmesi gereken noktalar
NavHost
öğesinin tam görünümünü alan bir hedefe navigate
(ör. bir <fragment>
hedefi) gittiğinizde, önceki hedefin yaşam döngüsü durdurulur ve SavedStateHandle
tarafından sağlanan LiveData
öğesine geri arama yapılması engellenir.
Bununla birlikte, bir iletişim kutusu hedefine gidildiğinde önceki hedef de ekranda görünür ve bu nedenle, geçerli hedef olmamasına rağmen yine STARTED
olur. Diğer bir deyişle, onViewCreated()
gibi yaşam döngüsü yöntemlerinden getCurrentBackStackEntry()
için yapılan çağrılar, bir yapılandırma değişikliğinden veya işlemin kaybedilmesi ve yeniden oluşturulmasından sonra (iletişim kutusu diğer hedefin üzerine geri yüklendiği için) iletişim kutusu hedefinin NavBackStackEntry
değerini döndürür. Bu nedenle, her zaman doğru NavBackStackEntry
kodunu kullandığınızdan emin olmak için hedefinizin kimliğiyle birlikte getBackStackEntry()
etiketini kullanmanız gerekir.
Bu aynı zamanda, LiveData
sonucunda ayarladığınız tüm Observer
öğelerinin, iletişim kutusu hedefleri hâlâ ekranda açık olsa bile tetikleneceği anlamına gelir. Sonucu, yalnızca iletişim kutusu hedefi kapatıldığında ve temel hedef geçerli hedef haline geldiğinde kontrol etmek isterseniz NavBackStackEntry
ile ilişkili Lifecycle
öğesini gözlemleyebilir ve sonucu yalnızca RESUMED
olduğunda alabilirsiniz.
Kotlin
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val navController = findNavController(); // After a configuration change or process death, the currentBackStackEntry // points to the dialog destination, so you must use getBackStackEntry() // with the specific ID of your destination to ensure we always // get the right NavBackStackEntry val navBackStackEntry = navController.getBackStackEntry(R.id.your_fragment) // Create our observer and add it to the NavBackStackEntry's lifecycle val observer = LifecycleEventObserver { _, event -> if (event == Lifecycle.Event.ON_RESUME && navBackStackEntry.savedStateHandle.contains("key")) { val result = navBackStackEntry.savedStateHandle.get<String>("key"); // Do something with the result } } navBackStackEntry.lifecycle.addObserver(observer) // As addObserver() does not automatically remove the observer, we // call removeObserver() manually when the view lifecycle is destroyed viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event -> if (event == Lifecycle.Event.ON_DESTROY) { navBackStackEntry.lifecycle.removeObserver(observer) } }) }
Java
@Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); NavController navController = NavHostFragment.findNavController(this); // After a configuration change or process death, the currentBackStackEntry // points to the dialog destination, so you must use getBackStackEntry() // with the specific ID of your destination to ensure we always // get the right NavBackStackEntry final NavBackStackEntry navBackStackEntry = navController.getBackStackEntry(R.id.your_fragment); // Create our observer and add it to the NavBackStackEntry's lifecycle final LifecycleEventObserver observer = new LifecycleEventObserver() { @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { if (event.equals(Lifecycle.Event.ON_RESUME) && navBackStackEntry.getSavedStateHandle().contains("key")) { String result = navBackStackEntry.getSavedStateHandle().get("key"); // Do something with the result } } }; navBackStackEntry.getLifecycle().addObserver(observer); // As addObserver() does not automatically remove the observer, we // call removeObserver() manually when the view lifecycle is destroyed getViewLifecycleOwner().getLifecycle().addObserver(new LifecycleEventObserver() { @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { if (event.equals(Lifecycle.Event.ON_DESTROY)) { navBackStackEntry.getLifecycle().removeObserver(observer) } } }); }
ViewModel ile hedefler arasında kullanıcı arayüzü ile ilgili verileri paylaşma
Geri gezinme yığını, yalnızca her bir hedef için değil, bağımsız hedefi içeren her bir üst gezinme grafiği için de bir NavBackStackEntry
depolar. Bu işlem, gezinme grafiğine ayarlanmış bir NavBackStackEntry
almanıza olanak tanır. Gezinme grafiği kapsamlı NavBackStackEntry
, gezinme grafiğine ayarlanmış bir ViewModel
oluşturmanın yolunu sağlar. Böylece, kullanıcı arayüzüyle ilgili verileri grafiğin hedefleri arasında paylaşabilirsiniz. Bu şekilde oluşturulan tüm ViewModel
nesneleri, ilişkili NavHost
ve ViewModelStore
öğeleri temizlenene veya gezinme grafiği arka yığından çıkana kadar aktif kalır.
Aşağıdaki örnekte, bir gezinme grafiğine ayarlanmış bir ViewModel
öğesinin nasıl alınacağı gösterilmektedir:
Kotlin
val viewModel: MyViewModel by navGraphViewModels(R.id.my_graph)
Java
NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.my_graph); MyViewModel viewModel = new ViewModelProvider(backStackEntry).get(MyViewModel.class);
Navigation 2.2.0 veya önceki bir sürümü kullanıyorsanız ViewModels ile Kayıtlı Durum'u kullanmak için aşağıdaki örnekte gösterildiği gibi kendi fabrikanızı sağlamanız gerekir:
Kotlin
val viewModel: MyViewModel by navGraphViewModels(R.id.my_graph) { SavedStateViewModelFactory(requireActivity().application, requireParentFragment()) }
Java
NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.my_graph); ViewModelProvider viewModelProvider = new ViewModelProvider( backStackEntry.getViewModelStore(), new SavedStateViewModelFactory( requireActivity().getApplication(), requireParentFragment())); MyViewModel myViewModel = provider.get(myViewModel.getClass());
ViewModel
hakkında daha fazla bilgi için ViewModel'e Genel Bakış bölümüne bakın.
Şişirilmiş gezinme grafiklerini değiştirme
Şişirilmiş bir gezinme grafiğini çalışma zamanında dinamik olarak değiştirebilirsiniz.
Örneğin, NavGraph
öğesine bağlı bir BottomNavigationView
varsa NavGraph
öğesinin varsayılan hedefi uygulama başlatılırken seçilen sekmeyi belirtir. Ancak, bir kullanıcı tercihinin uygulama başlangıcında yüklenmesini tercih edilen bir sekme belirtmesi gibi bu davranışı geçersiz kılmanız gerekebilir. Alternatif olarak, uygulamanızın başlangıç sekmesini geçmişteki kullanıcı davranışına göre değiştirmesi gerekebilir. Bu durumları, NavGraph
öğesinin varsayılan hedefini dinamik olarak belirterek destekleyebilirsiniz.
Şunu düşünün: NavGraph
:
<?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/nav_graph" app:startDestination="@id/home"> <fragment android:id="@+id/home" android:name="com.example.android.navigation.HomeFragment" android:label="fragment_home" tools:layout="@layout/fragment_home" /> <fragment android:id="@+id/location" android:name="com.example.android.navigation.LocationFragment" android:label="fragment_location" tools:layout="@layout/fragment_location" /> <fragment android:id="@+id/shop" android:name="com.example.android.navigation.ShopFragment" android:label="fragment_shop" tools:layout="@layout/fragment_shop" /> <fragment android:id="@+id/settings" android:name="com.example.android.navigation.SettingsFragment" android:label="fragment_settings" tools:layout="@layout/fragment_settings" /> </navigation>
Bu grafik yüklendiğinde app:startDestination
özelliği, HomeFragment
değerinin gösterileceğini belirtir. Başlangıç hedefini dinamik olarak geçersiz kılmak için aşağıdakileri yapın:
- Önce
NavGraph
şişirme işlemini manuel olarak yapın. - Başlangıç hedefini geçersiz kılın.
- Son olarak, grafiği
NavController
öğesine manuel olarak ekleyin.
Kotlin
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController val navGraph = navController.navInflater.inflate(R.navigation.bottom_nav_graph) navGraph.startDestination = R.id.shop navController.graph = navGraph binding.bottomNavView.setupWithNavController(navController)
Java
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager() .findFragmentById(R.id.nav_host_fragment); NavController navController = navHostFragment.getNavController(); NavGraph navGraph = navController.getNavInflater().inflate(R.navigation.bottom_nav_graph); navGraph.setStartDestination(R.id.shop); navController.setGraph(navGraph); NavigationUI.setupWithNavController(binding.bottomNavView, navController);
Artık uygulamanız başladığında HomeFragment
yerine ShopFragment
gösterilir.
NavController
, derin bağlantıları kullanırken derin bağlantı hedefi için otomatik olarak bir geri yığını oluşturur. Kullanıcı derin bağlantıya gidip daha sonra geriye giderse bir noktada başlangıç hedefine ulaşır. Önceki örnekte verilen tekniği kullanarak başlangıç hedefinin geçersiz kılınması, oluşturulan arka yığına doğru başlangıç hedefinin eklenmesini sağlar.
Bu tekniğin, gerektiğinde NavGraph
öğesinin diğer yönlerinin geçersiz kılınmasına da olanak tanıdığını unutmayın. Derin bağlantıları işleme, durumu geri yükleme ve grafiğinizin başlangıç hedefine taşıma sırasında doğru yapının kullanıldığından emin olmak için, grafikteki tüm değişikliklerin setGraph()
çağrısından önce yapılması gerekir.