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 ??
Leem.fin
źródło

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);
Deepak Goel
źródło
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());
            }
        }
    });
Ashakirov
źródło
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!

ptitvinou
źródło
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);
}
roghayeh hosseini
źródło
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()
Najlepszy artysta
źródło
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;
}
Erez
źródło
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);
Eduardo
źródło
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ę :)

Shirane85
źródło
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;
Czarny pas
źródło
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.

Cosmin Vacaru
źródło
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.

Arne Evertsson
źródło
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)
Wasilij Krawczenko
źródło
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);

Akbar Kazimov
źródło
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.

Michael
źródło
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 ...

Евгений Шевченко
źródło
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.

htafoya
źródło