pobierz najnowszy fragment w backstacku


104

Jak mogę dodać najnowszą instancję fragmentu do backstacku (jeśli nie znam tagu i identyfikatora fragmentu)?

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

Odpowiedzi:


156

Możesz użyć getName()metody, FragmentManager.BackStackEntryktóra została wprowadzona na poziomie API 14. Ta metoda zwróci znacznik, który był tym, którego użyłeś podczas dodawania fragmentu do backstack addTobackStack(tag).

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

Musisz się upewnić, że dodałeś fragment do stosu w ten sposób:

fragmentTransaction.addToBackStack(tag);

24
aby znaleźć fragment po tagu, należy go dodać / zastąpić tym samym tagiem. FragmentTransaction.add(int containerViewId, Fragment fragment, String tag)lub FragmentTransaction.replace(int containerViewId, Fragment fragment, String tag) doc
— Saqib

3
Problem z tym polega na tym, że jeśli masz fragment na stosie zaplecza dwukrotnie, nie możesz pobrać określonego fragmentu, gdy wszystko, co masz, to indeks lub encja backstackentry.
— Justin

14
Jaki jest sens nazywania go a, stackjeśli nie mogę uzyskać dostępu do fragmentu metodą pop?
— Kenny Worden


1
Nie wiem dlaczego, ale findFragmentByTag zwraca wartość null, nawet jeśli debugger wyraźnie pokazuje, że tag jest w porządku.
— htafoya

49
FragmentManager.findFragmentById(fragmentsContainerId) 

funkcja zwraca link do góry Fragmentw backstacku. Przykład użycia:

    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
Ta odpowiedź działa dobrze w moim projekcie, ponieważ dodaję każdy fragment oprócz fragmentu głównego do tylnego stosu. Ale myślę, że ta odpowiedź nie zadziała, jeśli ostatni dodany fragment nie zostanie dodany do backstacka.
— Arne Evertsson

40

Osobiście wypróbowałem wiele z tych rozwiązań i otrzymałem to działające rozwiązanie:

Dodaj tę metodę narzędziową, która będzie używana kilka razy poniżej, aby uzyskać liczbę fragmentów w twoim stosie:

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

Następnie, kiedy dodajesz / zastępujesz swój fragment metodą FragmentTransaction, wygeneruj unikalny tag do swojego fragmentu (np .: wykorzystując liczbę fragmentów w Twoim stosie):

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

Wreszcie, możesz znaleźć dowolny ze swoich fragmentów w swoim backstacku za pomocą tej metody:

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

Dlatego pobranie górnego fragmentu w swoim backstacku można łatwo osiągnąć, wywołując:

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

Mam nadzieję że to pomoże!


10

ta metoda pomocnicza pobiera fragment ze szczytu stosu:

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

1
Dzięki. Najbardziej elegancka odpowiedź. Dodano to tutaj dla miłośników Kotlin stackoverflow.com/a/47336504/1761406
— Shirane85

7

Kotlin

activity.supportFragmentManager.fragments.last()

4
Może być konieczne użycie .lastOrNull()w przypadku, gdy fragmentsjest pusty.
— Westy92

6

W pliku fragmentMananger znajduje się lista fragmentów. Należy pamiętać, że usunięcie fragmentu nie powoduje zmniejszenia rozmiaru listy (wpis fragmentu po prostu zmienia się na null). Dlatego poprawnym rozwiązaniem byłoby:

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
Nie wiarygodny. Trzy powody: 1) Jest to lista wszystkich fragmentów, o których wie menedżer fragmentów, a nie tylko tych na stosie. 2) Nie ma gwarancji, że menedżer fragmentów będzie dodawał nowe na końcu listy. Jasne, zrobi to w prostych testach, ale co, jeśli fragment zostanie usunięty, pozostawiając wartość null, a następnie w pewnych okolicznościach menedżer fragmentów zdecyduje się ponownie użyć tego pustego gniazda? Nie mówię, że tak, ale nie ma gwarancji, że nigdy tak się nie stanie, w żadnych okolicznościach. 3) Jeśli ty lub jakiś przyszły programista zacznie używać dołączania / odłączania do zarządzania fragmentami, nie będzie to pasowało do stosu.
— ToolmakerSteve

Cześć, dzięki za rozwiązanie, ale nie jest to piękne i łatwe
— Muhammad Ali

Wątpię, żeby to działało. getFragments()zwraca skróconą kolekcję fragmentów. Może ostatni jest widoczny, ale niewiele innych.
— CoolMind

5

Odpowiedź udzielona przez deepak goel nie działa dla mnie, ponieważ zawsze otrzymuję zero entry.getName();

To, co robię, to ustawiam Tag do fragmentu w ten sposób:

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

Gdzie ft to moja transakcja fragmentowa, a FRAGMENT_TAGto tag. Następnie używam tego kodu, aby uzyskać fragment:

Fragment prev_fragment = fragmentManager.findFragmentByTag(FRAGMENT_TAG);

To zadziała tylko wtedy, gdy nadasz całemu fragmentowi ten sam tag, co nie jest dobrym pomysłem, jeśli chcesz później znaleźć konkretny fragment.
— Shirane85

4

Właśnie wziąłem @roghayeh hosseini (poprawną) odpowiedź i zrobiłem to w Kotlinie dla tych tutaj w 2017 :)

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

* Należy to wywołać z wnętrza działania.

Cieszyć się :)


3

możesz użyć getBackStackEntryAt () . Aby dowiedzieć się, ile wpisów utrzymuje aktywność w backstacku, możesz użyć metody getBackStackEntryCount ()

int lastFragmentCount = getBackStackEntryCount() - 1;

11
Ale jak mogę zdobyć ostatni fragment w stosie? PopBackStackEntryAt () zwraca tylko instancję BackStackEntry, a NIE fragment
— Leem.fin

tak, masz rację, ale każdy BackStackEntry posiada i id, które możesz odzyskać za pomocą getId (). możesz użyć tego identyfikatora, aby odzyskać fragment
— Blackbelt

1
Aby zdobyć ostatni fragment: getBackStackEntryCount () - 1
— An-droid

3
Ta odpowiedź jest nieprawidłowa, widzę, że wpisy backstack mają identyfikator 0, więc nie mogę pobrać fragmentu według identyfikatora.
— Justin

1
To jest stare, ale dla każdego, kto tu błąka się: na tylnym stosie nie są fragmenty, ale transakcje fragmentowe, dlatego ta odpowiedź jest błędna
— maciekjanusz

3

Dodam coś do odpowiedzi Deepak Goel, ponieważ wiele osób, w tym ja, otrzymywało wartość zerową, używając jego metody. Najwyraźniej aby tag działał po dodaniu fragmentu do stosu, powinieneś to zrobić w ten sposób:

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

Musisz dwukrotnie dodać ten sam tag.

Skomentowałbym, ale nie mam 50 reputacji.


masz teraz 50 :)
— davidbilla

2

Zachować swoją tylną stos: myBackStack. Jako Addfragment do pliku FragmentManager, dodaj go również do myBackStack. W onBackStackChanged()pop od myBackStackkiedy jego długość jest większa niż getBackStackEntryCount.


2

Wygląda na to, że coś się zmieniło na lepsze, ponieważ poniższy kod u mnie działa idealnie, ale nie znalazłem go w udzielonych już odpowiedziach.

Kotlin:

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

Jawa:

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

2

Jeśli używasz addToBackStack(), możesz użyć następującego kodu.

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


1

Właściwie nie ma żadnego najnowszego fragmentu dodanego do stosu, ponieważ możesz dodać kilka lub fragmenty do stosu w jednej transakcji lub po prostu usunąć fragmenty bez dodawania nowego.

Jeśli naprawdę chcesz mieć stos fragmentów i mieć dostęp do fragmentu przez jego indeks w stosie, lepiej mieć warstwę abstrakcji nad FragmentManageri jego backstackiem. Oto jak możesz to zrobić:

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

Teraz zamiast dodawania i usuwania fragmentów dzwoniąc FragmentManagerbezpośrednio, należy użyć push(), replace()i pop()metody FragmentStackManager. I będziesz mógł uzyskać dostęp do najwyższego fragmentu, po prostu dzwoniąc stack.get(stack.size() - 1).

Ale jeśli lubisz hacki, mam inne sposoby na robienie podobnych rzeczy. Jedyne, o czym muszę wspomnieć, to to, że te hacki będą działać tylko z fragmentami wsparcia.

Pierwszy hack polega na dodaniu wszystkich aktywnych fragmentów do menedżera fragmentów. Jeśli po prostu zastąpisz fragmenty jeden po drugim i zdejmiesz ze stosu, ta metoda zwróci najwyższy fragment:

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

Drugie podejście jest bardziej hakerskie i pozwala na pobranie wszystkich fragmentów dodanych w ostatniej transakcji, dla której addToBackStackwywołano:

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

Zauważ, że w tym przypadku musisz umieścić tę klasę w android.support.v4.apppakiecie.


0

Lub możesz po prostu dodać tag podczas dodawania fragmentów odpowiadających ich zawartości i użyć prostego statycznego pola String (możesz również zapisać go w pakiecie instancji działania w metodzie onSaveInstanceState (Bundle)), aby przechowywać ostatnio dodany znacznik fragmentu i pobrać ten fragment przezTag () w dowolnym momencie ...


0

Najwyższa odpowiedź (Deepak Goel) nie działała dobrze dla mnie. W jakiś sposób tag nie został poprawnie dodany.

Skończyło się na tym, że wysłałem ID fragmentu przez przepływ (używając intencji) i pobrałem go bezpośrednio z menedżera fragmentów.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.