백 스택에서 최신 조각 가져 오기


104

백 스택에 추가 된 최신 조각 인스턴스를 얻으려면 어떻게해야합니까 (조각 태그 및 ID를 모르는 경우)?

FragmentManager fragManager = activity.getSupportFragmentManager();
FragmentTransaction fragTransacion = fragMgr.beginTransaction();

/****After add , replace fragments 
  (some of the fragments are add to backstack , some are not)***/

//HERE, How can I get the latest added fragment from backstack ??

답변:


156

API 레벨 14에서 도입 된 getName()메소드를 사용할 수 있습니다 FragmentManager.BackStackEntry.이 메소드는를 사용하여 백 스택에 Fragment를 추가 할 때 사용한 태그를 반환합니다 addTobackStack(tag).

int index = getActivity().getFragmentManager().getBackStackEntryCount() - 1
FragmentManager.BackStackEntry backEntry = getFragmentManager().getBackStackEntryAt(index);
String tag = backEntry.getName();
Fragment fragment = getFragmentManager().findFragmentByTag(tag);

다음과 같이 백 스택에 조각을 추가했는지 확인해야합니다.

fragmentTransaction.addToBackStack(tag);

24
태그별로 조각을 찾으려면 동일한 태그로 추가 / 교체해야합니다. FragmentTransaction.add(int containerViewId, Fragment fragment, String tag)또는 FragmentTransaction.replace(int containerViewId, Fragment fragment, String tag) 문서
Saqib

3
이 문제는 백 스택에 조각이 두 번 있으면 인덱스 또는 백 스택 항목 만 있으면 특정 조각을 검색 할 수 없다는 것입니다.
Justin

14
stackpop 메서드를 통해 조각에 액세스 할 수없는 경우 a라고 부르는 이유는 무엇입니까 ?
Kenny Worden 2015 년


1
이유는 모르겠지만 디버거가 태그가 정상임을 명확하게 표시하더라도 findFragmentByTag가 null을 반환합니다.
htafoya

49
FragmentManager.findFragmentById(fragmentsContainerId) 

함수Fragment백 스택의 맨 위로 링크를 반환합니다 . 사용 예 :

    fragmentManager.addOnBackStackChangedListener(new OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            Fragment fr = fragmentManager.findFragmentById(R.id.fragmentsContainer);
            if(fr!=null){
                Log.e("fragment=", fr.getClass().getSimpleName());
            }
        }
    });

2
이 답변은 루트 조각을 제외한 모든 조각을 백 스택에 추가하기 때문에 내 프로젝트에서 잘 작동합니다. 그러나 최근에 추가 된 조각이 백 스택에 추가되지 않으면이 답변이 작동하지 않을 것이라고 생각합니다.
Arne Evertsson 2014-08-15

40

나는 이러한 솔루션 중 많은 것을 개인적으로 시도했고 결국이 작동하는 솔루션으로 끝났습니다.

백 스택의 조각 수를 가져 오기 위해 아래에서 여러 번 사용할이 유틸리티 메서드를 추가합니다.

protected int getFragmentCount() {
    return getSupportFragmentManager().getBackStackEntryCount();
}

그런 다음 FragmentTransaction 메소드를 사용하여 프래그먼트를 추가 / 교체 할 때 프래그먼트에 고유 태그를 생성합니다 (예 : 스택의 프래그먼트 수 사용).

getSupportFragmentManager().beginTransaction().add(yourContainerId, yourFragment, Integer.toString(getFragmentCount()));

마지막으로이 방법을 사용하여 백 스택에서 조각을 찾을 수 있습니다.

private Fragment getFragmentAt(int index) {
    return getFragmentCount() > 0 ? getSupportFragmentManager().findFragmentByTag(Integer.toString(index)) : null;
}

따라서 다음을 호출하여 백 스택에서 최상위 조각을 쉽게 가져올 수 있습니다.

protected Fragment getCurrentFragment() {
    return getFragmentAt(getFragmentCount() - 1);
}

도움이 되었기를 바랍니다!


10

이 도우미 메서드는 스택 상단에서 조각을 가져옵니다.

public Fragment getTopFragment() {
    if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
        return null;
    }
    String fragmentTag = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1).getName();
    return getSupportFragmentManager().findFragmentByTag(fragmentTag);
}

1
감사. 가장 우아한 대답. Kotlin 애호가를 위해 여기에 추가됨 stackoverflow.com/a/47336504/1761406
Shirane85


6

fragmentMananger에 조각 목록이 있습니다. 조각을 제거해도 목록 크기가 줄어들지는 않습니다 (조각 항목이 null로 변경됨). 따라서 유효한 솔루션은 다음과 같습니다.

public Fragment getTopFragment() {
 List<Fragment> fragentList = fragmentManager.getFragments();
 Fragment top = null;
  for (int i = fragentList.size() -1; i>=0 ; i--) {
   top = (Fragment) fragentList.get(i);
     if (top != null) {
       return top;
     }
   }
 return top;
}

2
신뢰할 수 없습니다. 세 가지 이유 : 1) 이것은 스택에있는 조각뿐만 아니라 조각 관리자가 알고있는 모든 조각의 목록입니다. 2) 프래그먼트 관리자가 목록 끝에 새 항목을 계속 추가한다는 보장은 없습니다. 물론, 간단한 테스트에서 그렇게 할 것입니다.하지만 만약 프래그먼트가 제거되어 널을 남겨두고 어떤 상황에서 프래그먼트 관리자가 빈 슬롯을 재사용하기로 결정하면 어떻게 될까요? 그렇다고 말하지는 않지만 어떤 상황에서도 결코 그렇게 될 것이라는 보장은 없습니다. 3) 당신이나 미래의 프로그래머가 조각을 관리하기 위해 연결 / 분리를 사용하기 시작하면 스택과 일치하지 않습니다.
ToolmakerSteve

안녕하세요, 솔루션에 대한 감사하지만 아름다운하지 않고 쉽게
무하마드 알리

나는 그것이 작동하는 해결책이라고 의심합니다. getFragments()단축 된 조각 모음을 반환합니다. 마지막 하나가 보일 수 있지만 다른 것은 많지 않습니다.
CoolMind

5

나는 항상 null을 받기 때문에 deepak goel이 제공하는 대답은 나를 위해 작동하지 않습니다 entry.getName().

내가하는 일은 다음과 같이 조각에 태그를 설정하는 것입니다.

ft.add(R.id.fragment_container, fragmentIn, FRAGMENT_TAG);

ft는 내 조각 트랜잭션이고 FRAGMENT_TAG태그입니다. 그런 다음이 코드를 사용하여 조각을 가져옵니다.

Fragment prev_fragment = fragmentManager.findFragmentByTag(FRAGMENT_TAG);

이것은 모든 조각에 동일한 태그를 제공하는 경우에만 작동하며 나중에 특정 조각을 찾고자하는 경우에는 좋지 않습니다.
Shirane85

4

@roghayeh hosseini (올바른) 답변을 받아 2017 년에 여기있는 사람들을 위해 Kotlin에서 만들었습니다. :)

fun getTopFragment(): Fragment? {
    supportFragmentManager.run {
        return when (backStackEntryCount) {
            0 -> null
            else -> findFragmentByTag(getBackStackEntryAt(backStackEntryCount - 1).name)
        }
    }
}

* 활동 내에서 호출해야합니다.

즐겨 :)


3

getBackStackEntryAt () 사용할 수 있습니다 . 활동이 백 스택에 얼마나 많은 항목을 보유하고 있는지 알기 위해 getBackStackEntryCount ()를 사용할 수 있습니다.

int lastFragmentCount = getBackStackEntryCount() - 1;

11
그러나 백 스택에서 마지막 조각을 어떻게 얻을 수 있습니까 ?? popBackStackEntryAt는 () 만 BackStackEntry 인스턴스를 반환하지 조각
Leem.fin

예, 맞지만 모든 BackStackEntry는 getId ()로 검색 할 수있는 ID와 ID를 보유합니다. 이 ID를 사용하여 조각을 검색 할 수 있습니다
Blackbelt

1
1 - getBackStackEntryCount () : 마지막 조각 얻으려면
한 - 드로이드

3
이 대답은 잘못되었습니다. 백 스택 항목의 ID가 0이므로 ID로 조각을 검색 할 수 없습니다.
Justin

1
이것은 오래되었지만 여기를 헤매는 모든 사람들을위한 것입니다. 백 스택에는 조각이 아니라 조각 트랜잭션이 있기 때문에이 대답이 잘못된 것입니다
maciekjanusz

3

저를 포함한 많은 사람들이 그의 방법을 사용하여 null을 얻었으므로 Deepak Goel의 답변 에 무언가를 추가 하겠습니다. 백 스택에 조각을 추가 할 때 태그가 작동하도록하려면 다음과 같이해야합니다.

getSupportFragmentManager.beginTransaction().replace(R.id.container_id,FragmentName,TAG_NAME).addToBackStack(TAG_NAME).commit();

동일한 태그를 두 번 추가해야합니다.

댓글을 달았을 텐데 평판이 50 명은 아니에요.


당신은 지금 50을 얻었습니다 :)
davidbilla

2

자신의 백 스택 유지 : myBackStack. 당신이로 Add받는 조각 FragmentManager, 또한 그것을하기 위해 추가 myBackStack. 에서 onBackStackChanged()에서 팝 myBackStack의 길이보다 큰 경우 getBackStackEntryCount.


2

아래 코드가 저에게 완벽하게 작동하기 때문에 뭔가 더 나은 것으로 보이지만 이미 제공된 답변에서 찾지 못했습니다.

Kotlin :

supportFragmentManager.fragments[supportFragmentManager.fragments.size - 1]

자바:

getSupportFragmentManager().getFragments()
.get(getSupportFragmentManager().getFragments().size() - 1)

2

을 사용 addToBackStack()하면 다음 코드를 사용할 수 있습니다.

List<Fragment> fragments = fragmentManager.getFragments(); activeFragment = fragments.get(fragments.size() - 1);


1

실제로 스택에 추가 된 최신 조각이 없습니다. 단일 트랜잭션에서 여러 조각 또는 조각을 스택에 추가하거나 새 조각을 추가하지 않고 조각 만 제거 할 수 있기 때문입니다.

정말로 조각 스택을 갖고 스택의 인덱스로 조각에 액세스 할 수 있도록하려면 FragmentManager및 해당 백 스택에 대한 추상화 계층을 갖는 것이 좋습니다. 방법은 다음과 같습니다.

public class FragmentStackManager {
  private final FragmentManager fragmentManager;
  private final int containerId;

  private final List<Fragment> fragments = new ArrayList<>();

  public FragmentStackManager(final FragmentManager fragmentManager,
      final int containerId) {
    this.fragmentManager = fragmentManager;
    this.containerId = containerId;
  }

  public Parcelable saveState() {
    final Bundle state = new Bundle(fragments.size());
    for (int i = 0, count = fragments.size(); i < count; ++i) {
      fragmentManager.putFragment(state, Integer.toString(i), fragments.get(i));
    }
    return state;
  }

  public void restoreState(final Parcelable state) {
    if (state instanceof Bundle) {
      final Bundle bundle = (Bundle) state;
      int index = 0;
      while (true) {
        final Fragment fragment =
            fragmentManager.getFragment(bundle, Integer.toString(index));
        if (fragment == null) {
          break;
        }

        fragments.add(fragment);
        index += 1;
      }
    }
  }

  public void replace(final Fragment fragment) {
    fragmentManager.popBackStackImmediate(
        null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    fragmentManager.beginTransaction()
        .replace(containerId, fragment)
        .addToBackStack(null)
        .commit();
    fragmentManager.executePendingTransactions();

    fragments.clear();
    fragments.add(fragment);
  }

  public void push(final Fragment fragment) {
    fragmentManager
        .beginTransaction()
        .replace(containerId, fragment)
        .addToBackStack(null)
        .commit();
    fragmentManager.executePendingTransactions();

    fragments.add(fragment);
  }

  public boolean pop() {
    if (isEmpty()) {
      return false;
    }

    fragmentManager.popBackStackImmediate();

    fragments.remove(fragments.size() - 1);
    return true;
  }

  public boolean isEmpty() {
    return fragments.isEmpty();
  }

  public int size() {
    return fragments.size();
  }

  public Fragment getFragment(final int index) {
    return fragments.get(index);
  }
}

이제 다음을 호출하여 조각을 추가하고 제거하는 대신 FragmentManager 직접, 당신은 사용해야합니다 push(), replace()그리고 pop()방법 FragmentStackManager. 그리고 당신은 호출하여 최상위 조각에 액세스 할 수 있습니다stack.get(stack.size() - 1) .

하지만 해킹을 좋아한다면 비슷한 일을하는 다른 방법이 필요합니다. 내가 언급해야 할 유일한 것은 이러한 해킹이 지원 조각에서만 작동한다는 것입니다.

첫 번째 해킹은 모든 활성 프래그먼트를 프래그먼트 관리자에 추가하는 것입니다. 조각을 하나씩 교체하고 스택에서 팝하면이 메서드는 최상위 조각을 반환합니다.

public class BackStackHelper {
  public static List<Fragment> getTopFragments(
      final FragmentManager fragmentManager) {
    final List<Fragment> fragments = fragmentManager.getFragments();
    final List<Fragment> topFragments = new ArrayList<>();

    for (final Fragment fragment : fragments) {
      if (fragment != null && fragment.isResumed()) {
        topFragments.add(fragment);
      }
    }

    return topFragments;
  }
}

두 번째 접근 방식은 이벤트가 좀 더 해키이며 마지막 트랜잭션에서 추가 된 모든 조각을 가져올 수 있습니다. addToBackStack 호출 .

package android.support.v4.app;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class BackStackHelper {
  public static List<Fragment> getTopFragments(
      final FragmentManager fragmentManager) {
    if (fragmentManager.getBackStackEntryCount() == 0) {
      return Collections.emptyList();
    }

    final List<Fragment> fragments = new ArrayList<>();

    final int count = fragmentManager.getBackStackEntryCount();
    final BackStackRecord record =
        (BackStackRecord) fragmentManager.getBackStackEntryAt(count - 1);
    BackStackRecord.Op op = record.mHead;
    while (op != null) {
      switch (op.cmd) {
        case BackStackRecord.OP_ADD:
        case BackStackRecord.OP_REPLACE:
        case BackStackRecord.OP_SHOW:
        case BackStackRecord.OP_ATTACH:
          fragments.add(op.fragment);
      }
      op = op.next;
    }

    return fragments;
  }
}

이 경우이 클래스를 android.support.v4.app패키지 에 넣어야 합니다.


0

또는 콘텐츠에 해당하는 조각을 추가 할 때 태그를 추가하고 간단한 정적 문자열 필드 (onSaveInstanceState (Bundle) 메서드의 활동 인스턴스 번들에 저장할 수도 있음)를 사용하여 마지막으로 추가 된 조각 태그를 유지하고이 조각을 태그 ()로 가져올 수 있습니다. 언제든 필요할 때 ...


0

가장 높은 (Deepak Goel) 답변은 저에게 잘 맞지 않았습니다. 어떻게 든 태그가 제대로 추가되지 않았습니다.

결국 흐름을 통해 조각의 ID를 보내고 (인 텐트 사용) 조각 관리자에서 직접 검색했습니다.

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