Получить последний фрагмент в backstack
Как я могу получить последний экземпляр фрагмента, добавленный в backstack (если я не знаю тег фрагмента и 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 ??
Ответы
Ответ 1
Вы можете использовать метод 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);
Вам нужно убедиться, что вы добавили фрагмент в заднюю часть, например:
fragmentTransaction.addToBackStack(tag);
Ответ 2
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());
}
}
});
Ответ 3
I personnaly попробовал многие из этих решений и закончил с этим рабочим решением:
Добавьте этот метод утилиты, который будет использоваться несколько раз ниже, чтобы получить количество фрагментов в вашей задней части:
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);
}
Надеюсь, это поможет!
Ответ 4
В фрагментаторе есть список фрагментов. Имейте в виду, что удаление фрагмента не уменьшает размер списка (запись фрагмента превращается в нуль). Поэтому допустимым решением было бы следующее:
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;
}
Ответ 5
Ответ, данный deepak goel, не работает для меня, потому что я всегда получаю null от entry.getName()
;
Что я делаю, так это установить тег на фрагмент следующим образом:
ft.add(R.id.fragment_container, fragmentIn, FRAGMENT_TAG);
Где ft - моя транзакция фрагмента, а FRAGMENT_TAG
- тег. Затем я использую этот код для получения фрагмента:
Fragment prev_fragment = fragmentManager.findFragmentByTag(FRAGMENT_TAG);
Ответ 6
Сохраните свой собственный задний стек: myBackStack
. Как вы Add
фрагмент для FragmentManager
, также добавьте его в myBackStack
. В onBackStackChanged()
поп из myBackStack
, когда его длина больше, чем getBackStackEntryCount
.
Ответ 7
вы можете использовать getBackStackEntryAt(). Чтобы узнать, сколько записей в операции выполняется в backstack, вы можете использовать getBackStackEntryCount()
int lastFragmentCount = getBackStackEntryCount() - 1;
Ответ 8
На самом деле в стек не добавляется последний фрагмент, потому что вы можете добавить несколько или фрагменты в стек в одной транзакции или просто удалить фрагменты без добавления нового.
Если вы действительно хотите иметь стек фрагментов и иметь доступ к фрагменту по его индексу в стеке, вам лучше иметь слой абстракции над 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
.
Ответ 9
Или вы можете просто добавить тег при добавлении фрагментов, соответствующих их содержимому, и использовать простое статическое поле String (также вы можете сохранить его в наборе экземпляров активности в методе onSaveInstanceState (Bundle)), чтобы сохранить последний добавленный тег фрагмента и получить этот фрагмент byTag() в любое время, когда вам нужно...
Ответ 10
Самый высокий (Deepak Goel) ответ не помог мне. Каким-то образом тег не был добавлен должным образом.
В итоге я просто отправил идентификатор фрагмента через поток (используя намерения) и извлек его непосредственно из диспетчера фрагментов.
Ответ 11
этот вспомогательный метод получает фрагмент сверху стека:
public Fragment getTopFragment() {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
return null;
}
String fragmentTag = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1).getName();
return getSupportFragmentManager().findFragmentByTag(fragmentTag);
}
Ответ 12
Просто взял @roghayeh hosseini (правильный) ответ и сделал его в Котлине для тех, кто здесь, в 2017 году:)
fun getTopFragment(): Fragment? {
supportFragmentManager.run {
return when (backStackEntryCount) {
0 -> null
else -> findFragmentByTag(getBackStackEntryAt(backStackEntryCount - 1).name)
}
}
}
* Это должно вызываться изнутри Activity.
Наслаждайтесь:)