dapatkan fragmen terbaru di backstack

104

Bagaimana saya bisa mendapatkan instance fragmen terbaru yang ditambahkan di backstack (jika saya tidak tahu tag & id fragmen)?

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
sumber

Jawaban:

156

Anda dapat menggunakan getName()metode FragmentManager.BackStackEntryyang diperkenalkan di API level 14. Metode ini akan mengembalikan tag yang digunakan saat Anda menambahkan Fragmen ke backstack addTobackStack(tag).

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

Anda perlu memastikan bahwa Anda menambahkan fragmen ke backstack seperti ini:

fragmentTransaction.addToBackStack(tag);
Deepak Goel
sumber
24
untuk menemukan fragmen demi tag maka harus ditambahkan / diganti dengan tag yang sama. FragmentTransaction.add(int containerViewId, Fragment fragment, String tag)atau FragmentTransaction.replace(int containerViewId, Fragment fragment, String tag) dok
Saqib
3
Masalahnya adalah jika Anda memiliki fragmen di back-stack dua kali, Anda tidak dapat mengambil fragmen tertentu jika yang Anda miliki hanyalah entitas index atau backstackentry.
Justin
14
Apa gunanya menyebutnya sebagai stackjika saya tidak dapat mengakses fragmen melalui metode pop?
Kenny Worden
1
Saya tidak tahu mengapa tetapi findFragmentByTag mengembalikan null, bahkan ketika debugger dengan jelas menunjukkan bahwa tagnya ok.
htafoya
49
FragmentManager.findFragmentById(fragmentsContainerId) 

fungsi mengembalikan tautan ke atas Fragmentdi backstack. Contoh penggunaan:

    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
sumber
2
Jawaban ini berfungsi dengan baik dalam proyek saya karena saya menambahkan setiap fragmen kecuali fragmen root ke back-stack. Tapi saya rasa jawaban ini tidak akan berfungsi jika fragmen terbaru yang ditambahkan tidak ditambahkan ke backstack.
Arne Evertsson
40

Saya pribadi mencoba banyak solusi tersebut dan berakhir dengan solusi yang berfungsi ini:

Tambahkan metode utilitas ini yang akan digunakan beberapa kali di bawah ini untuk mendapatkan jumlah fragmen di backstack Anda:

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

Kemudian, saat Anda menambahkan / mengganti fragmen menggunakan metode FragmentTransaction, buat tag unik ke fragmen Anda (misalnya: dengan menggunakan jumlah fragmen di tumpukan Anda):

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

Terakhir, Anda dapat menemukan salah satu fragmen Anda di backstack dengan metode ini:

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

Oleh karena itu, mengambil fragmen teratas di backstack Anda dapat dengan mudah dilakukan dengan memanggil:

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

Semoga ini membantu!

ptitvinou
sumber
10

metode pembantu ini mendapatkan fragmen dari atas tumpukan:

public Fragment getTopFragment() {
    if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
        return null;
    }
    String fragmentTag = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1).getName();
    return getSupportFragmentManager().findFragmentByTag(fragmentTag);
}
roghayeh hosseini
sumber
1
Terima kasih. Jawaban paling elegan. Ditambahkan di sini untuk pecinta Kotlin stackoverflow.com/a/47336504/1761406
Shirane85
7

Kotlin

activity.supportFragmentManager.fragments.last()
Artis Terbaik
sumber
4
Anda mungkin perlu menggunakan .lastOrNull()jika fragmentskosong.
Westy92
6

Ada daftar fragmen di fragmentMananger. Ketahuilah bahwa menghapus sebuah fragmen, tidak membuat ukuran daftar berkurang (entri fragmen hanya berubah menjadi null). Oleh karena itu, solusi yang valid adalah:

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
sumber
2
Tidak dapat diandalkan. Tiga alasan: 1) Ini adalah daftar semua fragmen yang diketahui pengelola fragmen, tidak hanya yang ada di tumpukan. 2) Tidak ada jaminan bahwa pengelola fragmen akan terus menambahkan yang baru di akhir daftar. Tentu, itu akan melakukannya dalam pengujian sederhana, tetapi bagaimana jika sebuah fragmen dihapus, meninggalkan nol, dan kemudian dalam beberapa keadaan manajer fragmen memutuskan untuk menggunakan kembali slot kosong itu? Tidak mengatakan demikian, tetapi tidak ada jaminan bahwa hal itu tidak akan pernah terjadi, dalam keadaan apa pun. 3) Jika Anda atau beberapa programmer masa depan mulai menggunakan lampirkan / lepas untuk mengelola fragmen, ini tidak akan cocok dengan tumpukan.
ToolmakerSteve
Hai, terima kasih atas solusinya tetapi tidak indah dan mudah
Muhammad Ali
Saya ragu ini adalah solutuin yang berfungsi. getFragments()mengembalikan koleksi fragmen yang dipersingkat. Mungkin yang terakhir terlihat, tapi tidak banyak yang lain.
CoolMind
5

Jawaban yang diberikan oleh deepak goel tidak berhasil untuk saya karena saya selalu mendapatkan null dari entry.getName();

Yang saya lakukan adalah menyetel Tag ke fragmen dengan cara ini:

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

Di mana ft adalah transaksi fragmen saya dan FRAGMENT_TAGadalah tag. Kemudian saya menggunakan kode ini untuk mendapatkan fragmen:

Fragment prev_fragment = fragmentManager.findFragmentByTag(FRAGMENT_TAG);
Eduardo
sumber
Ini hanya akan berfungsi jika Anda memberikan tag yang sama kepada semua fragmen, yang bukan merupakan ide yang baik jika Anda ingin menemukan fragmen tertentu nanti.
Shirane85
4

Baru saja mengambil jawaban @roghayeh hosseini (benar) dan membuatnya di Kotlin untuk mereka di sini pada tahun 2017 :)

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

* Ini harus dipanggil dari dalam Aktivitas.

Nikmati :)

Shirane85
sumber
3

Anda bisa menggunakan getBackStackEntryAt () . Untuk mengetahui berapa banyak entri yang ditahan aktivitas di backstack, Anda bisa menggunakan getBackStackEntryCount ()

int lastFragmentCount = getBackStackEntryCount() - 1;
Sabuk hitam
sumber
11
Tapi bagaimana saya bisa mendapatkan fragmen terakhir di backstack ?? PopBackStackEntryAt () hanya mengembalikan instance BackStackEntry, BUKAN fragmen
Leem.fin
ya Anda benar, tetapi setiap BackStackEntry memegang dan id yang dapat Anda ambil dengan getId (). Anda dapat menggunakan Id ini untuk mengambil fragmen
Blackbelt
1
Untuk mendapatkan fragmen terakhir: getBackStackEntryCount () - 1
An-droid
3
Jawaban ini salah, saya melihat entri backstack memiliki id 0, jadi tidak dapat mengambil fragmen berdasarkan id.
Justin
1
Ini sudah lama, tetapi untuk siapa pun yang berkeliaran di sini: back-stack tidak menyimpan fragmen, tetapi transaksi fragmen, itulah mengapa jawaban ini salah
maciekjanusz
3

Saya akan menambahkan sesuatu pada jawaban Deepak Goel karena banyak orang, termasuk saya, mendapatkan nilai nol dengan menggunakan metodenya. Rupanya untuk membuat tag berfungsi saat Anda menambahkan fragmen ke backstack Anda harus melakukannya seperti ini:

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

Anda perlu menambahkan tag yang sama dua kali.

Saya akan berkomentar tetapi saya tidak memiliki 50 reputasi.

Cosmin Vacaru
sumber
Anda mendapat 50 sekarang :)
davidbilla
2

Menjaga tumpukan belakang Anda sendiri: myBackStack. Saat Anda Addmembuat fragmen FragmentManager, tambahkan juga ke myBackStack. Di onBackStackChanged()pop dari myBackStacksaat panjangnya lebih dari getBackStackEntryCount.

Arne Evertsson
sumber
2

Sepertinya ada sesuatu yang berubah menjadi lebih baik, karena kode di bawah berfungsi dengan sempurna untuk saya, tetapi saya tidak menemukannya di jawaban yang sudah disediakan.

Kotlin:

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

Jawa:

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

Jika Anda menggunakan addToBackStack(), Anda dapat menggunakan kode berikut.

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

Akbar Kazimov
sumber
1

Sebenarnya tidak ada fragmen terbaru yang ditambahkan ke tumpukan karena Anda dapat menambahkan beberapa atau fragmen ke tumpukan dalam satu transaksi atau hanya menghapus fragmen tanpa menambahkan yang baru.

Jika Anda benar-benar ingin memiliki tumpukan fragmen dan dapat mengakses fragmen berdasarkan indeksnya di tumpukan, Anda sebaiknya memiliki lapisan abstraksi di atas FragmentManagerdan backstacknya. Inilah cara Anda melakukannya:

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

Sekarang bukan menambah dan menghapus fragmen dengan menelepon FragmentManagerlangsung, Anda harus menggunakan push(), replace()dan pop()metode FragmentStackManager. Dan Anda akan dapat mengakses fragmen paling atas hanya dengan menelepon stack.get(stack.size() - 1).

Tetapi jika Anda suka retas, saya harus cara lain untuk melakukan hal serupa. Satu-satunya hal yang harus saya sebutkan adalah bahwa peretasan ini hanya akan berfungsi dengan fragmen dukungan.

Peretasan pertama hanya untuk menambahkan semua fragmen aktif ke pengelola fragmen. Jika Anda hanya mengganti fragmen satu per satu dan mengeluarkannya dari tumpukan, metode ini akan mengembalikan fragmen paling atas:

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

Pendekatan kedua adalah event more hacky dan memungkinkan Anda untuk mendapatkan semua fragmen yang ditambahkan dalam transaksi terakhir yang addToBackStacktelah dipanggil:

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

Harap perhatikan bahwa dalam hal ini Anda harus memasukkan kelas ini ke dalam android.support.v4.apppaket.

Michael
sumber
0

Atau Anda bisa menambahkan tag saat menambahkan fragmen yang sesuai dengan kontennya dan menggunakan kolom String statis sederhana (Anda juga dapat menyimpannya dalam paket instance aktivitas dalam metode onSaveInstanceState (Bundle)) untuk menahan tag fragmen yang terakhir ditambahkan dan mendapatkan fragmen byTag () ini kapan pun Anda membutuhkan ...

Евгений Шевченко
sumber
0

Jawaban (Deepak Goel) tertinggi tidak bekerja dengan baik untuk saya. Entah bagaimana, tag tersebut tidak ditambahkan dengan benar.

Saya akhirnya hanya mengirim ID fragmen melalui alur (menggunakan maksud) dan mengambilnya langsung dari pengelola fragmen.

htafoya.dll
sumber