Android'de başka bir parçaya gittikten sonra gezinme yığını nasıl temizlenir


122

Android'de yeni Gezinme Mimarisi Bileşenini kullanıyorum ve yeni bir parçaya geçtikten sonra gezinme yığınını temizlemekte takılı kaldım.

Örnek: loginFragment'tayım ve bu parçanın, ana bölüme gittiğimde yığından temizlenmesini istiyorum, böylece kullanıcı geri düğmesine bastığında loginFragment'a geri dönmeyecek.

Gezinmek için basit bir NavHostFragment.findNavController (Fragment) .navigate (R.id.homeFragment) kullanıyorum.

Mevcut Kod:

mAuth.signInWithCredential(credential)
            .addOnCompleteListener(getActivity(), new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        NavHostFragment.findNavController(LoginFragment.this).navigate(R.id.homeFragment);
                    } else {
                        Log.w(TAG, "signInWithCredential:failure", task.getException());
                    }
                }
            });

Ben kullanarak çalıştı NavOptions içinde gezindiğini () , ancak geri düğmesi hala loginFragment beni geri gönderiyor

NavOptions.Builder navBuilder = new NavOptions.Builder();
NavOptions navOptions = navBuilder.setPopUpTo(R.id.homeFragment, false).build();   
             NavHostFragment.findNavController(LoginFragment.this).navigate(R.id.homeFragment, null, navOptions);

Sen kullanabilirsiniz popBackStackveya katmayan LoginFragmentsağlamak backstack için nulliçin addToBackStack(null);ve yeni ile değiştirinFragment
Yupi

Lütfen yayınınızı düzenleyin ve gezinmek için kullandığınız kodu ekleyin
Barns

Sorumu düzenledim ve kodumu ekledim
Youssef El Behi

@ Yupi'nin iyi bir öneri sunduğunu düşünüyorum. Ya da senaryonuza en uygun olanı sağlayabilir ve bu navigate()yöntemi kullanabilirsiniznavigate(int resId, Bundle args, NavOptions navOptions)NavOptions
Barns

The NavOptions'ı kullanmayı denedim, ancak geri düğmesi beni hala loginFragment'a geri gönderiyor
Youssef El Behi

Yanıtlar:


181

İlk olarak, nitelikleri app:popUpTo='your_nav_graph_id've app:popUpToInclusive="true"eylem etiketine ekleyin .

<fragment
    android:id="@+id/signInFragment"
    android:name="com.glee.incog2.android.fragment.SignInFragment"
    android:label="fragment_sign_in"
    tools:layout="@layout/fragment_sign_in" >
    <action
        android:id="@+id/action_signInFragment_to_usersFragment"
        app:destination="@id/usersFragment"
        app:launchSingleTop="true"
        app:popUpTo="@+id/main_nav_graph"
        app:popUpToInclusive="true" />
</fragment>

İkinci olarak, yukarıdaki eylemi parametre olarak kullanarak hedefe gidin.

findNavController(fragment).navigate(
     SignInFragmentDirections.actionSignInFragmentToUserNameFragment())

Daha fazla bilgi için belgelere bakın .

NOT : Yöntemi kullanarak gezinirseniz navigate(@IdRes int resId), istediğiniz sonucu alamazsınız. Bu nedenle yöntemi kullandım navigate(@NonNull NavDirections directions).


1
ClearTask olarak en iyi yanıt, Android Navigasyon Bileşeni'nin yeni sürümlerinde artık kullanımdan kaldırıldı!
Michał Ziobro

14
Eylemin kimliği de bu şekilde kullanılabilirfindNavController(fragment).navigate(R.id.action_signInFragment_to_usersFragment)
Calin

1
Müthiş! Ancak, şimdi yedek / yukarı glifim var, ancak ona basmak hiçbir şey yapmıyor. Bunu da kaldırmanın temiz bir yolu nedir?
Danimarka Han

6
Sanırım bu cevabın anahtarı, "popUpTo" nun (mevcut parçanız ile bu argümana aktardığınız kimliğin ilk oluşumu arasındaki tüm parçaları kaldırır) gezinme grafiğinin kimliğine ayarlanmış olmasıdır . Backstack'i etkili bir şekilde tamamen temizliyor. Sadece bu yorumu ekledim çünkü tam olarak böyle açıkladığını görmedim ve aradığım buydu. 1!
Scott O'Toole

7
NOT : Safe-args gradle'ı dahil etmediyseniz, "Directions" sınıfı oluşturulmayacaktır. Daha fazla bilgi için burayı
Jaydip Kalkani

28

Sorunuzun özellikle Pop Behavior / Pop To / app: popUpTo (xml olarak) kullanımıyla ilgili olduğunu düşünüyorum.

Belgelerde,
navigasyona başlamadan önce belirli bir hedefe gidin. Bu, bu hedef bulunana kadar arka yığından eşleşmeyen tüm hedefleri çıkarır.

Örnek (Basit İş avcılık uygulaması)
benim start_screen_nav grafiği şu şekildedir:

startScreenFragment (start) -> loginFragment -> EmployerMainFragment

                            -> loginFragment -> JobSeekerMainFragment

Ben gitmek istiyorum EmployerMainFragmentve tüm pop dahil startScreenFragment sonra kod olacaktır:

        <action
            android:id="@+id/action_loginFragment_to_employerMainFragment"
            app:destination="@id/employerMainFragment"

            app:popUpTo="@+id/startScreenFragment"
            app:popUpToInclusive="true" />

Ben gitmek istiyorum EmployerMainFragmentve tüm pop hariç startScreenFragment sonra kod olacaktır:

        <action
            android:id="@+id/action_loginFragment_to_employerMainFragment"
            app:destination="@id/employerMainFragment"

            app:popUpTo="@+id/startScreenFragment"/>

Gezinmek EmployerMainFragmentve pop yapmak istiyorsam loginFragmentama istemiyorsam startScreenFragment kod şöyle olacaktır:

        <action
            android:id="@+id/action_loginFragment_to_employerMainFragment"
            app:destination="@id/employerMainFragment"

            app:popUpTo="@+id/loginFragment"
            app:popUpToInclusive="true"/>

VEYA

        <action
            android:id="@+id/action_loginFragment_to_employerMainFragment"
            app:destination="@id/employerMainFragment"

            app:popUpTo="@+id/startScreenFragment"/>

Bunu XML yerine programlı olarak nasıl yapabilirim?
IgorGanapolsky

28

Benim durumumda, yeni bir parça açmadan önce arka yığındaki her şeyi kaldırmam gerekiyordu, bu yüzden bu kodu kullandım

navController.popBackStack(R.id.fragment_apps, true);
navController.navigate(R.id.fragment_company);

İlk satır, benim durumumda belirtilen parçaya ulaşıncaya kadar arka Yığını kaldırır, bu ana bölümdür, böylece tüm arka yığını tamamen kaldırır ve kullanıcı fragment_company'de geri tıkladığında uygulamayı kapatır.


1
Nedir fragment_apps??
IgorGanapolsky

1
Mevcut parça. Sanki fragmentOne üzerindeyseniz ve fragmentTwo'ya gitmek istiyorsanız navController.popBackStack (R.id.fragmentOne, true) kullanmanız gerekir; navController.navigate (R.id.fragmentTwo);
Bbeni

14

NOT: Görevi temizle kullanımdan kaldırıldı, resmi açıklama

Bu yöntem kullanımdan kaldırılmıştır. NavController grafiğinin kimliğiyle setPopUpTo (int, boolean) kullanın ve dahil öğesini true olarak ayarlayın.

Eski Cevap

Kodda tüm bu zabıta geçmesi istemiyorsan, sadece kontrol edebilirsiniz Clear Taskiçinde Launch Optionseylem özelliklerinde.

Başlatma ayarları

Düzenleme: Android Studio 3.2 Beta 5'ten itibaren, Görevi Temizle artık Başlatma Seçenekleri penceresinde görünmez, ancak yine de gezinmenin XML kodunda, eylem etiketinde, ekleyerek kullanabilirsiniz.

app:clearTask="true"

ClearTask xml atıfta bulunulan düzeltme mesajında ​​söylediği gibi grafiğin kök kimliğini kullanmalısınız: "popUpTo'yu grafiğinizin köküne ayarlayın ve popUpToInclusive'i kullanın". Bunu böyle yaptım ve findNavController () ile aynı istenen davranışı elde ettim. Navigate (@IdRes resId, bundle)
artnest

PopUpTo ve popUpToInclusive'in ayarlanması için önerilen yaklaşımın kullanılması, başlangıç ​​hedefi dışındaki hedefler arasındaki eylemler için işe yaramıyor gibi görünüyor: issuetracker.google.com/issues/116831650
hsson

Aslında başlangıç ​​hedefiyle çalışmadığı, sinir bozucu bir sorunla karşılaşıyorum.
Mel

Patlatmak istediğiniz parçayı bilmiyorsanız bunu nasıl yaparsınız? Örneğin, yeni bir öğe oluşturan bir parçam var. Oluşturduktan sonra bu öğenin ayrıntı görünümünü göstermek istiyorum. Ancak kullanıcının daha sonra yaratma parçasına geri dönmesini değil, önceki görünüme dönmesini istemiyorum. Bu, tüm öğelerin bir listesi veya yenisinin dayandığı farklı bir öğe olabilir. O zaman tek seçenek ClearTask mı?
findusl

Hayır, aslında artık kullanılmamalı. Bunun yerine, popUpTo'yu kapsamlı bir şekilde kullanmalısınız. PopUpTo kullanım bulgularımla cevabı çok yakında güncelleyeceğim.
Mel

5

Yeni Navigasyon Mimarisi Bileşeni ile bazı parçalar için Navigasyonda YUKARI nasıl devre dışı bırakılır ? Sayesinde nihayet anladım.

NavOption olarak .setClearTask (true) seçeneğini belirtmem gerekiyordu.

mAuth.signInWithCredential(credential)
            .addOnCompleteListener(getActivity(), new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        Log.d(TAG, "signInWithCredential:success");


                        NavOptions.Builder navBuilder = new NavOptions.Builder();
                        NavOptions navOptions = navBuilder.setClearTask(true).build();
                        NavHostFragment.findNavController(LoginFragment.this).navigate(R.id.homeFragment,null,navOptions);
                    } else {
                        Log.w(TAG, "signInWithCredential:failure", task.getException());

                    }

                }
            });

2
Görmekten mutluyum kullandığınız benim önerim uygulamak başardık navigate(int resId, Bundle args, NavOptions navOptions)veNavOptions
Ahırlar

Evet. Teşekkürler @Barns
Youssef El Behi

14
evet "setClearTask" kullanımdan kaldırıldı, ancak bunun yerine şunları kullanabilirsiniz: val navOptions = NavOptions.Builder().setPopUpTo(R.id.my_current_frag, true).build() findNavController().navigate(R.id.my_next_frag, null, navOptions)
Pablo Reyes

1
@ c-an çalışmalıdır. Muhtemelen yanlış bir hedef fragmentId kullanıyorsunuzdur (örneğin R.id.my_next_frag, giriş veya açılış ekranı gibi olabilir); Eğer popBack sadece bir istiyorum da, sen kullanabilirsiniz: NavHostFragment.findNavController(this).popBackStack().
Pablo Reyes

2
@PabloReyes Bu doğru cevap. Sadece hangi parçanın en son kaldırılacağını belirtin: Bu yığına sahip olduğunuzu söyleyin: Fragment_1 Fragment_2 Fragment_3 Şu anda Fragment_3'dasınız ve Fragment_4'e gitmek ve diğer tüm parçaları temizlemek istiyorsunuz. Xml: app: popUpTo = "@ id / Fragment_1" app: popUpToInclusive = "true"
user3193413

5

İşte bunu nasıl yapıyorum.

 //here the R.id refer to the fragment one wants to pop back once pressed back from the newly  navigated fragment
 val navOption = NavOptions.Builder().setPopUpTo(R.id.startScorecardFragment, false).build()

//now how to navigate to new fragment
Navigation.findNavController(this, R.id.my_nav_host_fragment)
                    .navigate(R.id.instoredBestPractice, null, navOption)

Kapsayıcı bayrağınız neden false?
IgorGanapolsky

2
Belgelere göre inclusive boolean: true to also pop the given destination from the back stack Bu yüzden, kapsayıcıyı yanlış olarak ayarladım çünkü mevcut parçayı yığından çıkarmak istemiyorum.
Abdul Rahman Shamair

4
    NavController navController 
    =Navigation.findNavController(requireActivity(),          
    R.id.nav_host_fragment);// initialize navcontroller

    if (navController.getCurrentDestination().getId() == 
     R.id.my_current_frag) //for avoid crash
  {
    NavDirections action = 
    DailyInfoSelectorFragmentDirections.actionGoToDestionationFragment();

    //for clear current fragment from stack
    NavOptions options = new 
    NavOptions.Builder().setPopUpTo(R.id.my_current_frag, true).build();
    navController.navigate(action, options);
    }

1

Temel aktivitenin geri basılmasını şu şekilde geçersiz kılabilirsiniz:

override fun onBackPressed() {

  val navigationController = nav_host_fragment.findNavController()
  if (navigationController.currentDestination?.id == R.id.firstFragment) {
    finish()
  } else if (navigationController.currentDestination?.id == R.id.secondFragment) {
    // do nothing
  } else {
    super.onBackPressed()
  }

}

1

Not: Bu, asıl soruyla ilgili olmayabilir.

Bu yaklaşım, Navigasyonda bakım yapmak için bir parçanın tek bir örneğine ihtiyaç duyulduğunda yararlı olacaktır .

// imports
import androidx.navigation.navOptions

// navigate to fragment
navController.navigate(R.id.nav_single_instance_fragment, null,
                            navOptions {
                                popUpTo = R.id.nav_single_instance_fragment
                                launchSingleTop = true
                            })

İşte navOptionsDSL ve içe aktarılması gerekiyor. Bu cevabın verildiği sırada, Navigasyon Kullanıcı Arayüzünün aşağıdaki kademeli sürümlerini kullanıyorum .

    def nav_version = "2.2.0"
    implementation "androidx.navigation:navigation-ui:$nav_version"
    implementation "androidx.navigation:navigation-fragment:$nav_version"
    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"

0

Geri düğmesinin başlangıç ​​parçama geri dönmesini önlemek için bir süre uğraştım, bu benim durumumda yalnızca bir kez görünmesi gereken bir giriş mesajıydı.

Kolay çözüm, bir kullanıcının kalması gereken hedefe işaret küresel bir eylem . Sen ayarlamak zorunda app:popUpTo="..."kapalı yakalanırsam istediğiniz hedefe ayarlayın - Doğru. Benim durumumda bu benim giriş mesajımdı. Ayrıca ayarlaapp:popUpToInclusive="true"


0

Bunu küçük bir örnekle açıklayabilirim. Çalışanların listesi ve sildiği iki parça var. Çalışanı sil seçeneğinde, iki tıklama olayını iptal et ve sil. İptal'e tıklarsam, çalışan listesi ekranına geri döner ve sil'e tıklarsam önceki tüm arka yığınları temizlemek ve çalışan listesi ekranına gitmek istiyorum.

Önceki ekrana gitmek için:

<action
        android:id="@+id/action_deleteEmployeeFragment_to_employeesListFragment2"
        app:destination="@id/employeesListFragment"/>


    btn_cancel.setOnClickListener {
                it.findNavController().popBackStack()
            }

Önceki tüm arka yığınları temizlemek ve yeni ekrana gitmek için:

<action
        android:id="@+id/action_deleteEmployeeFragment_to_employeesListFragment2"
        app:destination="@id/employeesListFragment"
        app:popUpTo="@id/employeesListFragment"
        app:popUpToInclusive="true"
        app:launchSingleTop="true" />


 btn_submit.setOnClickListener {
                   it.findNavController().navigate(DeleteEmployeeFragmentDirections.actionDeleteEmployeeFragmentToEmployeesListFragment2())
        }

Daha fazla referans için: Jetpack Navigasyon Örneği


0

Şu kadar basit yapabilirsiniz:

getFragmentManager().popBackStack();

Sayımı kontrol etmek istiyorsanız, şunları yapabilirsiniz:

getFragmentManager().getBackStackEntryCount()
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.