깊이 중첩 된 스택을 떠날 때 프래그먼트 백 스택을 정리하는 올바른 방법입니까?


130

Android 호환성 라이브러리를 사용하여 조각을 구현하고 조각에 다른 조각을 발사하는 버튼이 포함되도록 레이아웃 샘플을 확장했습니다.

왼쪽의 선택 창에는 5 개의 선택 가능한 항목이 있습니다 A B C D E.

FragmentTransaction:replace세부 정보 창에서을 통해 조각을로드합니다.a b c d e

이제 세부 정보 창에도 e다른 조각을로드하는 버튼이 포함되도록 조각 을 확장했습니다 e1. e다음과 같이 프래그먼트 의 onClick 메소드 에서이 작업을 수행했습니다 .

FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.replace(R.id.details_frag, newFrag);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();

다음을 선택하면

E - e - e1 - D - E

그런 다음 조각 e이 세부 정보 창에 있습니다. 이것은 괜찮고 내가 원하는 것입니다. 그러나이 back시점에서 버튼을 누르면 아무것도하지 않습니다. e1여전히 스택에 있기 때문에 두 번 클릭해야 합니다. 또한 클릭 한 후 onCreateView에서 null 포인터 예외가 발생했습니다.

이 문제를 '해결'하기 위해 A B C D E선택 될 때마다 다음을 추가했습니다 .

FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {
    fm.popBackStack();
}

이것이 올바른 해결책인지 아니면 다른 것을 해야하는지 궁금하십니까?

답변:


252

의도 된 동작에 따라이 문제를 해결할 수있는 몇 가지 방법이 있지만이 링크는 모든 최상의 솔루션을 제공해야하며 당연히 Dianne Hackborn의 솔루션이 아닙니다.

http://groups.google.com/group/android-developers/browse_thread/thread/d2a5c203dad6ec42

기본적으로 다음과 같은 옵션이 있습니다

  • 초기 백 스택 상태의 이름을 사용하고를 사용하십시오 FragmentManager.popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • FragmentManager.getBackStackEntryCount()/ getBackStackEntryAt().getId() 를 사용 하여 백 스택에서 첫 번째 항목의 ID를 검색하십시오 FragmentManager.popBackStack(int id, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • FragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) 전체 백 스택을 팝해야합니다 ... 나는 그 문서가 잘못되었다고 생각합니다. (실제로 전달하는 경우를 다루지 않는 것 같습니다 POP_BACK_STACK_INCLUSIVE),

이것은 무엇을 의미 하는가? FragmentManager.getBackStackEntryCount () / getBackStackEntryAt (). getId ()
dannyroa

4
두 번째는 나를 위해 일했다. 전체 스택을 지우는 의미 : getSupportFragmentManager (). popBackStack (getSupportFragmentManager (). getBackStackEntryAt (0) .getId (), FragmentManager.POP_BACK_STACK_INCLUSIVE);
NickL

@JorgeGarcia는 popbackstack 후 이전 버전을 다시 시작하지 않고 조각을 마칠 수 있습니다.
duggu

popBackStack ()이 비동기이므로 popBackStackImmediate () 버전도 있습니다. 즉, 메소드를 호출하는 순간에 정리가 수행되지 않습니다.
Genc

6
그룹이 스팸으로 금지되어 있으며 링크에 액세스 할 수 없다고 주장합니다. (다른 사람이 다른 리소스를 가지고 있습니까?
EpicPandaForce

61

모든 스택 항목을 팝하지 않으려면 다른 깨끗한 솔루션 ...

getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
getSupportFragmentManager().beginTransaction().replace(R.id.home_activity_container, fragmentInstance).addToBackStack(null).commit();

이렇게하면 먼저 스택을 정리 한 다음 새 조각을로드하므로 특정 지점에서 스택에 단일 조각 만 있습니다.


1
이것은 매우 나쁜 : getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);A는 교체하기 전에 ()을 조각 통화를로드하기 때문에 onCreateView(), onActivityCreated()등 복원과 조각 즉시 나쁜 Destroing. 프래그먼트는 예를 들어 수신기를 등록 할 수 있습니다. 이것은 성능에 영향을줍니다.
VasileM

@VasileM, 자세히 설명해 주시겠습니까? 어떤 경우에 나쁜가요? 무의식적 인 행동 때문 FragmentTransaction입니까? 잘못된 조각 스택의 성능이 나쁜 것입니까?
CoolMind

27

Joachim 답변 덕분에 코드를 사용하여 모든 백 스택 항목을 마침내 지 웁니다.

// In your FragmentActivity use getSupprotFragmentManager() to get the FragmentManager.

// Clear all back stack.
int backStackCount = getSupportFragmentManager().getBackStackEntryCount();
for (int i = 0; i < backStackCount; i++) {

    // Get the back stack fragment id.
    int backStackId = getSupportFragmentManager().getBackStackEntryAt(i).getId();

    getSupportFragmentManager().popBackStack(backStackId, 
        FragmentManager.POP_BACK_STACK_INCLUSIVE);

} /* end of for */

18
왜 루프를 사용합니까? 나를 위해 FragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE) 모든 백 스택 항목을 지 웠습니다 ...
Marek

3
@Marek, 때로는 모든 조각을 제거하지 않아도되므로 루프가 적합합니다.
CoolMind

1
@ CoolMind, 여전히 이해가되지 않습니다. popBackStack(backStackId, INCLUSIVE)모든 프래그먼트 (상태)를 backStackId로 다시 팝하므로 가장 낮은 팝을 터뜨리면 모든 높은 프래그먼트 (상태) i가 동시에 팝업됩니다. 루프의 요점은 무엇입니까?
LarsH

@LarsH, 네 말이 맞아. stackoverflow.com/a/59158254/2914140을 참조하십시오 . 다른 조각을 필수 태그에 넣으려면 먼저 addToBackStack ( tag )을 사용 하여 조각을 추가해야합니다 .
CoolMind

7

Backstack 청소에 대해 많은 연구를 마쳤으며 마지막으로 Transaction BackStack 및 해당 관리를 참조하십시오 . 여기에 가장 적합한 솔루션이 있습니다.

 // CLEAR BACK STACK.
    private void clearBackStack() {
        final FragmentManager fragmentManager = getSupportFragmentManager();
        while (fragmentManager.getBackStackEntryCount() != 0) {
            fragmentManager.popBackStackImmediate();
        }
    }

위의 방법은 백 스택의 모든 트랜잭션을 반복하고 한 번에 하나씩 즉시 제거합니다.

참고 : 위의 코드는 때때로 작동하지 않으며이 코드로 인해 ANR에 직면 하므로 시도하지 마십시오.

아래 업데이트 방법은 백 스택에서 해당 "이름"의 모든 조각을 제거합니다.

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack("name",FragmentManager.POP_BACK_STACK_INCLUSIVE);
  • name null 이외의 경우, 이것은 이전의 이전 상태의 이름입니다. 발견되면 해당 상태까지의 모든 상태가 팝업됩니다. 그만큼
  • POP_BACK_STACK_INCLUSIVE 플래그를 사용하여 명명 된 상태 자체의 팝 여부를 제어 할 수 있습니다. null의 경우, 최상 상태 만이 팝됩니다.

한 번에 하나씩 제거하는 이유를 모르겠습니다. 다른 솔루션 대신이 솔루션을 선택한 이유가 있습니까? 한 번에 한 번에 하나씩 제거해야하는 이유가 있습니까?
miva2

어떤 방법 thair 한 번 참조에 가기 backstack 제거하는 developer.android.com/reference/android/app/...
록쉬

3

while 루프를 사용하는 코드와 비슷한 코드를 사용하고 있지만 모든 루프에서 항목 수를 호출합니다. 그래서 다소 느리다고 가정합니다.

FragmentManager manager = getFragmentManager();
while (manager.getBackStackEntryCount() > 0){
        manager.popBackStackImmediate();
    }

0

백 스택 오프 프래그먼트 오프 방법LarsH 에 의해 작성된 바와 같이 , 이 방법을 사용하여 여러 프래그먼트를 위에서 아래로 특정 태그 ( 태그 된 프래그먼트와 함께)로 팝할 수 있습니다 .

fragmentManager?.popBackStack ("frag", FragmentManager.POP_BACK_STACK_INCLUSIVE);

"frag"를 조각의 태그로 대체하십시오. 먼저 다음을 사용하여 조각을 백 스택에 추가해야합니다.

fragmentTransaction.addToBackStack("frag")

로 프래그먼트를 추가하면 addToBackStack(null)그런 식으로 프래그먼트가 팝업되지 않습니다.


-4
    // pop back stack all the way
    final FragmentManager fm = getSherlockActivity().getSupportFragmentManager();
    int entryCount = fm.getBackStackEntryCount(); 
    while (entryCount-- > 0) {
        fm.popBackStack();
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.