Android에서 다른 조각으로 이동 한 후 탐색 스택을 지우는 방법


122

Android에서 새로운 탐색 아키텍처 구성 요소 를 사용 하고 있으며 새 조각으로 이동 한 후 탐색 스택을 지우는 데 갇혀 있습니다.

예 : 나는 loginFragment에 있고 홈 프래그먼트로 이동할 때 스택에서이 프래그먼트를 지워서 사용자가 뒤로 버튼을 눌렀을 때 loginFragment로 돌아 가지 않도록하고 싶습니다.

탐색하려면 간단한 NavHostFragment.findNavController (Fragment) .navigate (R.id.homeFragment) 를 사용하고 있습니다.

현재 코드 :

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());
                    }
                }
            });

navigate () 에서 NavOptions 를 사용해 보았지만 뒤로 버튼이 여전히 나를 loginFragment로 다시 보냅니다.

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);

당신은 사용할 수 있습니다 popBackStack또는 추가하지 마십시오 LoginFragment제공 가기 backstack하기 nulladdToBackStack(null);하고 새로 교체Fragment
Yupi

게시물을 편집하고 탐색에 사용중인 코드를 추가하십시오
Barns

내 질문을 편집하고 내 코드 추가
유세프 엘 Behi

@Yupi가 좋은 제안을했다고 생각합니다. 아니면 사용할 수있는 navigate()등의 방법 navigate(int resId, Bundle args, NavOptions navOptions)과 제공 NavOptions에 가장 잘 senario에 맞는 것을
질러

NavOptions를 사용해 보았지만 뒤로 버튼이 여전히 나를 loginFragment로 돌려 보내고 있습니다
Youssef El Behi

답변:


180

먼저 속성 app:popUpTo='your_nav_graph_id'app:popUpToInclusive="true"작업 태그를 추가합니다 .

<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>

둘째, 위의 작업을 매개 변수로 사용하여 목적지로 이동합니다.

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

문서 보기 정보 를 참조하십시오.

참고 : method를 사용하여 탐색 navigate(@IdRes int resId)하면 원하는 결과를 얻을 수 없습니다. 따라서 방법을 사용했습니다 navigate(@NonNull NavDirections directions).


1
clearTask라는 베스트 답변은 이제 Android 탐색 구성 요소의 새 버전에서 더 이상 사용되지 않습니다!
Michał Ziobro

14
하나는 같은 작업의 ID를 사용할 수 있습니다findNavController(fragment).navigate(R.id.action_signInFragment_to_usersFragment)
칼린

1
대박! 그러나 이제 백업 / 업 글리프가 있지만 눌러도 아무 작업도 수행되지 않습니다. 그것도 제거하는 깨끗한 방법은 무엇입니까?
Danish Khan

6
이 답변의 핵심은 "popUpTo"(현재 조각과이 인수에 전달하는 ID의 첫 번째 발생 사이의 모든 조각을 제거함)가 탐색 그래프 자체ID로 설정된다는 점에 있다고 생각 합니다 . 백 스택을 효과적으로 완전히 제거합니다. 이 코멘트를 추가하는 이유는 이것이 정확히 이와 같이 설명 된 것을 보지 못했기 때문에 제가 찾고 있던 것이 었습니다. +1!
Scott O'Toole

7
참고 : safe-args gradle을 포함하지 않은 경우 "Directions"클래스가 생성되지 않습니다. 더 많은 정보를 원하시면 여기를
Jaydip Kalkani 19.06.22

28

귀하의 질문은 특히 Pop Behavior / Pop To / app : popUpTo (xml에서)를 사용하는 방법과 관련이 있다고 생각합니다.

문서에서
탐색하기 전에 지정된 목적지로 팝업합니다. 이 대상을 찾을 때까지 백 스택에서 일치하지 않는 모든 대상을 팝합니다.

예제 (간단한 구직 앱)
start_screen_nav 그래프는 다음과 같습니다.

startScreenFragment (start) -> loginFragment -> EmployerMainFragment

                            -> loginFragment -> JobSeekerMainFragment

탐색 EmployerMainFragment하고 모든 것을startScreenFragment하려면 코드는 다음과 같습니다.

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

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

탐색 EmployerMainFragment하고 모두 제외 하고 싶다면 startScreenFragment코드는 다음과 같습니다.

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

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

내가으로 이동하려면 EmployerMainFragment및 팝업 loginFragment하지 startScreenFragment 다음 코드는 다음과 같습니다

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

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

또는

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

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

XML 대신 프로그래밍 방식으로이 작업을 수행하는 방법은 무엇입니까?
IgorGanapolsky

28

제 경우에는 새 조각을 열기 전에 백 스택의 모든 것을 제거해야했기 때문에이 코드를 사용했습니다.

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

첫 번째 줄은 내 경우에 지정된 조각에 도달 할 때까지 백 스택을 제거하므로 홈 조각이므로 모든 백 스택을 완전히 제거하고 사용자가 fragment_company에서 다시 클릭하면 앱을 닫습니다.


1
무엇입니까 fragment_apps?
IgorGanapolsky

1
현재 조각입니다. u가 fragmentOne에 있고 fragmentTwo로 이동하려는 경우와 같습니다. navController.popBackStack (R.id.fragmentOne, true); navController.navigate (R.id.fragmentTwo);
Bbeni

14

참고 : 작업 지우기는 더 이상 사용되지 않으며 공식 설명은

이 메소드는 더 이상 사용되지 않습니다. NavController의 그래프 ID와 함께 setPopUpTo (int, boolean)를 사용하고 inclusive를 true로 설정하십시오.

이전 답변

당신은 코드의 모든 솜털을 통과 싶어하지 않는 경우, 당신은 단순히 확인할 수 있습니다 Clear Task에서 Launch Options작업의 속성이다.

시작 옵션

편집 : Android Studio 3.2 Beta 5부터 Clear Task가 더 이상 Launch Options 창에 표시되지 않지만 작업 태그에서 다음을 추가하여 탐색의 XML 코드에서 계속 사용할 수 있습니다.

app:clearTask="true"

clearTask xml attributeeprecation 메시지에 "popUpTo를 그래프의 루트로 설정하고 popUpToInclusive를 사용하십시오"라는 메시지가 표시되므로 그래프 루트의 ID를 사용해야합니다. 나는 이렇게했고 findNavController (). navigate (@IdRes resId, bundle)으로 동일한 원하는 동작을 달성했습니다
artnest

popUpTo 및 popUpToInclusive 설정의 권장 방법을 사용하면 시작 대상이 아닌 다른 대상 간의 작업에 대해 작동하지 않는 것 같습니다. issuetracker.google.com/issues/116831650
hsson

실제로 시작 목적지에서 작동하지 않는 문제가 발생하여 실망 스럽습니다.
Mel

팝하려는 조각을 모르는 경우 어떻게해야합니까? 예를 들어 새 항목을 만드는 조각이 있습니다. 만든 후이 항목의 세부 정보보기를 표시하고 싶습니다. 그러나 사용자가 나중에 조각 만들기로 돌아 가지 않고 이전보기로 돌아 가기를 원하지 않습니다. 이는 모든 항목의 목록이거나 새 항목의 기반이되는 다른 항목 일 수 있습니다. 그렇다면 clearTask가 유일한 옵션입니까?
findusl

아니요, 실제로 더 이상 사용해서는 안됩니다. 대신 popUpTo를 포괄적으로 사용해야합니다. popUpTo 사용법에 대한 결과로 곧 답변을 업데이트 할 것입니다.
Mel

5

새 탐색 아키텍처 구성 요소를 사용하여 일부 조각에 대해 탐색에서 UP을 비활성화하는 방법 덕분에 마침내 알아 냈습니다 .

NavOption으로 .setClearTask (true)를 지정해야했습니다.

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
볼 다행 사용하여 내 제안을 구현할 수 있었다 navigate(int resId, Bundle args, NavOptions navOptions)NavOptions
질러

예. 감사 @Barns
유세프 엘 Behi

14
예 "setClearTask"는 더 이상 사용되지 않지만 대신 다음을 사용할 수 있습니다. 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 작동합니다. 아마도 잘못된 대상 fragmentId를 사용하고있을 것입니다 (예 : R.id.my_next_frag로그인 또는 스플래시 화면과 같을 수 있음). 또한 하나만 popBack하려면 다음을 사용할 수 있습니다 NavHostFragment.findNavController(this).popBackStack()..
Pablo Reyes

2
@PabloReyes 정답입니다. 마지막으로 제거 할 조각을 지정하기 만하면됩니다. 다음 스택이 있다고 가정합니다. Fragment_1 Fragment_2 Fragment_3 이제 Fragment_3에 있으며 Fragment_4로 이동하여 다른 모든 조각을 지우려고합니다. 탐색 xml에서 지정하기 만하면됩니다. app : popUpTo = "@ id / Fragment_1"app : popUpToInclusive = "true"
user3193413

5

여기에 내가 그것을 수행하는 방법이 있습니다.

 //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)

포괄적 인 깃발 false입니까?
IgorGanapolsky

2
문서 에 따르면 inclusive boolean: true to also pop the given destination from the back stack 스택에서 현재 조각을 팝하고 싶지 않기 때문에 inclusive를 false로 설정했습니다.
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

다음과 같이 기본 활동의 뒤로 누름을 재정의 할 수 있습니다.

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

참고 : 이것은 실제 질문과 관련이 없을 수 있습니다.

이 접근 방식은 Navigation 에서 유지 관리하는 데 단편의 단일 인스턴스가 필요한 경우에 유용합니다 .

// 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
                            })

여기에 navOptionsDSL이 있으며 가져와야합니다. 이 답변의 시점에 탐색 UI 의 다음 gradle 버전을 사용하고 있습니다.

    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

나는 뒤로 버튼이 내 시작 조각으로 돌아가는 것을 막기 위해 한동안 애 썼는데, 내 경우에는 한 번만 나타나야하는 인트로 메시지였습니다.

쉬운 해결책은 사용자가 머물러야하는 목적지를 가리키는 전역 액션 을 만드는 것이 었 습니다. 당신은 설정해야 app:popUpTo="..."떨어져 튀어 얻을 당신이 원하는 목적지로 설정 - 올바르게. 제 경우에는 제 소개 메시지였습니다. 또한 설정app:popUpToInclusive="true"


0

나는 이것을 작은 예를 통해 설명 할 수있다. 두 조각의 직원이 직원을 나열하고 삭제합니다. 직원 삭제에는 취소 및 삭제 두 개의 클릭 이벤트가 있습니다. 취소를 클릭하면 직원 목록 화면으로 돌아가고 삭제를 클릭하면 이전 백 스택을 모두 지우고 직원 목록 화면으로 이동합니다.

이전 화면으로 이동 :

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


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

이전 백 스택을 모두 지우고 새 화면으로 이동하려면 :

<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())
        }

더 많은 참조 : Jetpack 탐색 예


0

다음과 같이 간단하게 할 수 있습니다.

getFragmentManager().popBackStack();

카운트를 확인하려면 다음과 같이 할 수 있습니다.

getFragmentManager().getBackStackEntryCount()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.