it-roy-ru.com

получить последний фрагмент в backstack

Как я могу получить последний экземпляр фрагмента, добавленный в backstack (если я не знаю тег фрагмента и идентификатор)?

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 ??
89
Leem.fin

Вы можете использовать метод getName() для FragmentManager.BackStackEntry, который был представлен на уровне API 14. Этот метод вернет тег, который вы использовали при добавлении фрагмента в backstack с помощью addTobackStack(tag).

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

Вам нужно убедиться, что вы добавили фрагмент в backstack следующим образом:

fragmentTransaction.addToBackStack(tag);
144
Deepak Goel
FragmentManager.findFragmentById(fragmentsContainerId) 

функция возвращает ссылку на верхнюю Fragment в backstack. Пример использования:

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

Я лично попробовал многие из этих решений и в итоге получил это рабочее решение:

Добавьте этот метод утилиты, который будет использоваться несколько раз ниже, чтобы получить количество фрагментов в вашем бэкстеке:

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

Затем, когда вы добавляете/заменяете свой фрагмент, используя метод FragmentTransaction, генерируйте уникальный тег для вашего фрагмента (например, используя количество фрагментов в вашем стеке):

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

Наконец, вы можете найти любой из ваших фрагментов в вашем backstack с помощью этого метода:

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

Следовательно, выборка верхнего фрагмента в вашем backstack может быть легко достигнута путем вызова:

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

Надеюсь это поможет!

37
ptitvinou

Существует список фрагментов в фрагменте Мэненджера. Помните, что удаление фрагмента не приводит к уменьшению размера списка (запись фрагмента просто обнуляется). Следовательно, правильное решение будет:

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;
}
6
Erez

Ответ, который дал Дипак Гоэль, не работает для меня, потому что я всегда получаю ноль от entry.getName();

Что я делаю, это устанавливаю тег для фрагмента следующим образом:

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

Где ft - моя транзакция фрагмента, а FRAGMENT_TAG - тег. Затем я использую этот код, чтобы получить фрагмент:

Fragment prev_fragment = fragmentManager.findFragmentByTag(FRAGMENT_TAG);
4
Eduardo

этот вспомогательный метод получает фрагмент из верхней части стека:

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

вы можете использовать getBackStackEntryAt () . Чтобы узнать, сколько записей содержит действие в бэкстеке, вы можете использовать getBackStackEntryCount ()

int lastFragmentCount = getBackStackEntryCount() - 1;
3
Blackbelt

Похоже, что-то изменилось в лучшую сторону, потому что приведенный ниже код отлично работает для меня, но я не нашел его в уже предоставленных ответах.

Котлин:

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

Джава:

getSupportFragmentManager().getFragments()
.get(getSupportFragmentManager().getFragments().size() - 1)
2
Vasily Kravchenko

Просто взял ответ @roghayeh hosseini (правильный) и сделал это в Котлине для тех, кто здесь в 2017 году :)

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

* Это должно быть вызвано из Деятельности.

Наслаждаться :)

2
Shirane85

Держите свой собственный стек обратно: myBackStack. Поскольку вы Add фрагмент в FragmentManager, также добавьте его в myBackStack. В onBackStackChanged() выскочить из myBackStack, когда его длина больше, чем getBackStackEntryCount.

2
Arne Evertsson

На самом деле в стек не добавляется последний фрагмент, потому что вы можете добавить несколько или фрагменты в стек за одну транзакцию или просто удалить фрагменты, не добавляя новый.

Если вы действительно хотите иметь стек фрагментов и иметь возможность доступа к фрагменту по его индексу в стеке, вам лучше иметь уровень абстракции над FragmentManager и его backstack. Вот как вы можете это сделать:

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.

1
Michael

Самый высокий ответ (Дипак Гоэль) не сработал для меня. Каким-то образом тег не был добавлен правильно.

В итоге я просто отправил идентификатор фрагмента через поток (используя намерения) и получил его непосредственно из менеджера фрагментов.

0
htafoya

Или вы можете просто добавить тег при добавлении фрагментов, соответствующих их содержимому, и использовать простое статическое поле String (также вы можете сохранить его в пакете экземпляра действия в методе onSaveInstanceState (Bundle)), чтобы сохранить последний добавленный тег фрагмента и получить этот фрагмент byTag () в любое время вам нужно ...

0