Как мне получить отображаемый в данный момент фрагмент?

Играю с фрагментами в Android.

Я знаю, что могу изменить фрагмент, используя следующий код:

FragmentManager fragMgr = getSupportFragmentManager();
FragmentTransaction fragTrans = fragMgr.beginTransaction();

MyFragment myFragment = new MyFragment(); //my custom fragment

fragTrans.replace(android.R.id.content, myFragment);
fragTrans.addToBackStack(null);
fragTrans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
fragTrans.commit();

Мой вопрос в том, как в файле Java получить текущий отображаемый экземпляр фрагмента?


person Leem.fin    schedule 15.02.2012    source источник
comment
Связанные - stackoverflow.com/a/21104084/80428   -  person Jay Wick    schedule 04.08.2015
comment
Возможный дубликат Получить текущий объект фрагмента   -  person Sruit A.Suk    schedule 06.03.2016


Ответы (50)


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

fragTrans.replace(android.R.id.content, myFragment, "MY_FRAGMENT");

... и позже, если вы хотите проверить, виден ли фрагмент:

MyFragment myFragment = (MyFragment)getSupportFragmentManager().findFragmentByTag("MY_FRAGMENT");
if (myFragment != null && myFragment.isVisible()) {
   // add your code here
}

См. Также http://developer.android.com/reference/android/app/Fragment.html

person ramdroid    schedule 15.02.2012
comment
Хорошо, но мне нужен способ немедленно получить текущий отображаемый экземпляр фрагмента, а не итеративно проверять все фрагменты, а затем решать, какой фрагмент теперь отображается на экране. Я думаю, что вашему ответу нужен мой код, чтобы итеративно проверять каждый из моих фрагментов и находить видимый ... - person Leem.fin; 15.02.2012
comment
Да, но одновременно может быть видно несколько фрагментов. Так что нет ничего лучше единственного активного фрагмента .... - person ramdroid; 15.02.2012
comment
Хорошо, даже если отображается несколько фрагментов, мне все равно нужен способ их получить ... и способ, который лучше, чем итеративная проверка каждого из моих фрагментов. Я беспокоюсь о том, чтобы получить им такой метод, как getDisplayedFragment (), но не уверен, есть ли такой метод в Android - person Leem.fin; 15.02.2012
comment
Я не знаю, почему это проблема для вас ... Обычно у вас есть только несколько фрагментов в действии, и на самом деле не должно быть проблемой проверить их, видны они или нет. - person ramdroid; 20.02.2012
comment
Разве это не дало бы NPE, если бы фрагмент еще не отображался? - person TrtG; 20.01.2014
comment
Если ваш телефон выключен, isVisible вернет false. Следовательно, этот метод не указывает правильность, если фрагмент находится на вершине стека. - person JacksOnF1re; 28.08.2014
comment
Проверьте, является ли myFragment нулевым, прежде чем проверять, виден ли он. if (myFragment! = null && myFragment.isVisible ()) {...} - person Michael Peterson; 03.03.2015
comment
fragTrans.replace (android.R.id.content, myFragment, MY_FRAGMENT); используется для установки тега. Но когда я позже нахожу фрагмент по TAG, он нулевой. Сводит меня с ума! - person user798719; 11.09.2015
comment
Вам также необходимо поместить ТЕГ в addToBackStack (). взгляните на ответ @Dmitry_L для этого случая. - person Shayan Amani; 13.01.2016
comment
Почему все поддерживают этот ответ? Конечно, это хороший фрагмент кода, но он не отвечает на вопрос, чтобы получить конкретный фрагмент по тегу. НО Аскер хочет отображаемый в данный момент фрагмент, что означает, что он не знает, какой фрагмент отображается. Да, может быть несколько фрагментов, но чтение вопроса означает, что в пользовательском интерфейсе отображается только 1 фрагмент .... Извините, пришлось проголосовать против, потому что он не отвечает на контекст вопроса. - person angryITguy; 26.05.2017
comment
Предположим, у меня есть 10 фрагментов, тогда мне нужно написать несколько строк кода для проверки того, какой фрагмент активен. есть ли лучший способ узнать, какой фрагмент активен сейчас, без многократной проверки и приведения типов. - person Ajit Kumar Dubey; 06.06.2018
comment
MainFragment myFragment = (MainFragment)getSupportFragmentManager().findFragmentById(R.id.frame_layout); if (myFragment != null && myFragment.isVisible()) { Log.d(TAG,"myFragment is opened"); } else { Log.d(TAG,"myFragment is not opened and null"); } @AjitKumarDubey попробуйте это, с помощью этого вам не нужно отслеживать каждый тег фрагмента. вместо этого используйте findFragmentById для поиска фрагмента и приведите его к имени класса, и у вас может быть условие для проверки каждого фрагмента. - person Pritesh Vishwakarma; 24.09.2018

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

  @Override
    public void onBackPressed() {
        super.onBackPressed();

         Fragment f = getActivity().getFragmentManager().findFragmentById(R.id.fragment_container);
      if(f instanceof CustomFragmentClass) 
        // do something with f
        ((CustomFragmentClass) f).doSomething();

    }

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

person Sev    schedule 05.07.2014
comment
Именно то, что я искал, имея дело с onBackPressed () после поворота экрана с помощью навигационного ящика. Спасибо, что вернулись, чтобы поделиться этим. - person ShortFuse; 27.08.2014
comment
Не выполняет ли findFragmentById внутреннюю итерацию по всем фрагментам? :) - person Andrew Senner; 24.05.2015
comment
в случае, если .getFragmentManager сообщает о несовместимом типе, как это было в моем случае, это потому, что я использовал android.support.app.v4.Fragment, и в этом случае правильный метод для использования - getSupportFragmentManager - person Răzvan Barbu; 28.07.2015
comment
или вы можете использовать findFragmentByTag() вместо findFragmentById, если вы указали тег для фрагмента при добавлении его в fragmentManager.beginTransaction() .add(containerID, frag, fragmentTag) .addToBackStack(fragmentTag) .commit(); - person DeltaCap019; 04.08.2015
comment
@AndrewSenner, он имеет в виду, что не хотел этого делать явно :) - person Farid; 21.03.2019

Вот мое решение, которое я считаю удобным для сценариев с низким фрагментом

public Fragment getVisibleFragment(){
    FragmentManager fragmentManager = MainActivity.this.getSupportFragmentManager();
    List<Fragment> fragments = fragmentManager.getFragments();
    if(fragments != null){
        for(Fragment fragment : fragments){
            if(fragment != null && fragment.isVisible())
                return fragment;
        }
    }
    return null;
}
person Matt Mombrea    schedule 10.10.2013
comment
fragment может иметь значение NULL в определенных сценариях, например, когда вы открываете задний стек. Так что лучше используйте if (fragment != null && fragment.isVisible()). - person cprcrack; 06.02.2014
comment
метод неполный, потому что возможно, что виден не только один фрагмент - person letroll; 04.02.2015
comment
Если фрагмент не виден, то fragmentManager.getFragments () вернет NULL, что приведет к тому, что NPE сообщит «Попытка вызвать метод интерфейса java.util.Iterator java.util.List.iterator ()» для ссылки на объект NULL. Следовательно, цикл for должен быть окружен простой проверкой: if (fragments! = Null) - person Pranav Mahajan; 14.12.2015
comment
Что делать, если видно более одного фрагмента? - person Shivaraj Patil; 30.06.2016
comment
@ShivarajPatil, В случае ActionBar видно больше 1 фрагмента, Вы нашли решение? - person user1324887; 31.07.2016
comment
'@ user1324887 nop, но вы можете вместо того, чтобы возвращать один фрагмент внутри цикла, добавлять фрагменты в список, например Список видимых фрагментов, и возвращать этот список и просматривать каждый из них. Не идеальное решение, и я его не тестировал. - person Shivaraj Patil; 31.07.2016
comment
Технически это должно быть отмечено как ответ, основанный на вопросе. Аскер хочет отображаемый в данный момент фрагмент, не зная, какой это фрагмент. Остальные ответы продолжают получать фрагменты по тегам - person angryITguy; 26.05.2017

Каждый раз, когда вы показываете фрагмент, вы должны поместить его тег в backstack:

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_ENTER_MASK);       
ft.add(R.id.primaryLayout, fragment, tag);
ft.addToBackStack(tag);
ft.commit();        

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

public BaseFragment getActiveFragment() {
    if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
        return null;
    }
    String tag = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1).getName();
    return (BaseFragment) getSupportFragmentManager().findFragmentByTag(tag);
}
person Dmitry_L    schedule 21.03.2013
comment
Я почти уверен, что этот метод не будет работать для фрагментов, используемых с ViewPager, поскольку они не добавляются с помощью тегов. Просто выбросил это туда. - person loeschg; 16.01.2014
comment
Это работает только тогда, когда вы вызываете addToBackStack(tag), но что, если вы не хотите добавлять фрагмент в задний стек? - person cprcrack; 06.02.2014
comment
Это работает, только если ваш тег совпадает с именем заднего стека, что кажется необычным. - person ; 05.03.2014
comment
Что произойдет, если вы добавите 5 фрагментов в одну транзакцию? - person Kevin Lam; 15.08.2014
comment
Может быть, неплохо сказать, что если вы вызываете addToBackStack (null) для некоторого фрагмента, где вам не нужно имя, метод getName () может вернуть null, и вы получите NPE. @ dpk, в документе говорится: Получите имя, которое было предоставлено FragmentTransaction.addToBackStack (String) при создании этой записи. Кроме того, добавьте нулевую проверку, если EntryCount равен 0, и вы попытаетесь получить верхнюю запись. - person JacksOnF1re; 28.08.2014

Котлинский путь;

val currentFragment = supportFragmentManager.fragments.last()
person Cafer Mert Ceyhan    schedule 22.02.2019
comment
Работает только с API 26 и выше - person ibit; 24.03.2019
comment
@ibit, что вы имеете в виду, когда работаете только с API 26 и выше? Я попробовал эмулятор API 19, работающий нормально. - person HendraWD; 03.04.2019
comment
@HendraWD ты прав! Я имел в виду функцию из getFragments() фреймворка, то есть API 26 и выше. - person ibit; 04.04.2019
comment
заботиться. Если до этого у вас нет стека фрагментов, это может вызвать пустое исключение! - person Jetwiz; 18.11.2019
comment
Это не работает? java.lang.ClassCastException: androidx.navigation.fragment.NavHostFragment не может быть преобразован во фрагмент - person coolcool1994; 03.05.2020
comment
Правильный способ: supportFragmentManager.fragments.last () ?. getChildFragmentManager () ?. getFragments () ?. get (0) - person coolcool1994; 03.05.2020

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

    FragmentManager fragManager = this.getSupportFragmentManager();
    int count = this.getSupportFragmentManager().getBackStackEntryCount();
    Fragment frag = fragManager.getFragments().get(count>0?count-1:count);
person tainy    schedule 09.06.2014
comment
Вы должны убедиться, что count ›0, чтобы get (count-1) не генерировал исключение IndexOutofBoundsException. - person kehers; 17.06.2014
comment
@tainy это не даст фрагмент, который был заменен, но не добавлен в backstack. Верно? Если да, то могу ли я получить его с помощью аргумента тега? - person cafebabe1991; 06.10.2015
comment
Вызов getFragments не даст вам фрагментов в том порядке, в котором они были добавлены, после того, как вы вызовете для него popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE) и добавите дополнительные фрагменты. - person LEHO; 05.04.2016
comment
если у активности есть более одного видимого фрагмента, ваш путь неверен. Например: ViewPager с фрагментами. как я знаю, getBackStackEntryCount () возвращает номер транзакции, а не количество фрагментов - person HungNM2; 04.01.2017
comment
Вы должны проверить fragManager.getFragments().size() вместо getBackStackEntryCount(), поскольку они не обязательно равны (как в моем случае). В противном случае вы можете получить сбой с IndexOutOfBoundsException - person RustamG; 31.01.2019

реактивный способ:

Observable.from(getSupportFragmentManager().getFragments())
    .filter(fragment -> fragment.isVisible())
    .subscribe(fragment1 -> {
        // Do something with it
    }, throwable1 -> {
        // 
    });
person localhost    schedule 26.04.2016
comment
как это реагирует? Вы используете наблюдаемый объект, но он будет генерировать только один раз - person Tim; 15.03.2018
comment
И это просто перебор. Простой усовершенствованный forloop будет делать то же самое, может быть, даже быстрее. - person Peterstev Uremgba; 17.04.2018
comment
использование реактивного потока только для потока api не так умно, на самом деле, как они сказали, это излишество, используйте Steam Java8 api, если вы хотите рассматривать список как поток и применять api фильтра - person AndroidLover; 24.07.2018

Мой метод основан на следующем:

MyFragment viewer = null;
    if(getFragmentManager().findFragmentByTag(MY_TAG_FRAGMENT) instanceOf MyFragment){
    viewer = (MyFragment) getFragmentManager().findFragmentByTag(MY_TAG_FRAGMENT);
}

Но может быть способ получше ...

person Thordax    schedule 15.02.2012
comment
Мой вопрос в том, как получить отображаемый в данный момент фрагмент, что означает, что может быть много фрагментов, я хочу получить только экземпляр текущего отображаемого, зачем использовать (MyFragment) ?? Я имею в виду, что это может быть любой фрагмент, отображаемый на экране ... и я хочу получить тот, который отображается в данный момент. - person Leem.fin; 15.02.2012
comment
MY_TAG_FRAGMENT - это тег фрагмента, который я создал перед использованием замены, например: fragmentTransaction.replace (R.id.FL_MyFragment, MyFragment, MY_TAG_FRAGMENT); - person Thordax; 15.02.2012
comment
Если у меня несколько фрагментов, могу ли я использовать один тег для всех фрагментов при вызове .replace (...)? - person Leem.fin; 15.02.2012
comment
Да, без проблем, используйте этот код: fragmentTransaction.replace (R.id.FL_MyFragment, MyFragment, MY_TAG_FRAGMENT); и все может пройти хорошо. - person Thordax; 15.02.2012
comment
Итак, если я использую один тег для всех фрагментов, как только я найду FragmentByTag (tag), он вернет мне текущий отображаемый фрагмент, я прав? - person Leem.fin; 15.02.2012
comment
Будьте осторожны, потому что вы получите ClassCastException, если попытаетесь получить фрагмент, сделав то, что я сказал в моем первом посте! - person Thordax; 15.02.2012
comment
Что ж, я действительно не понимаю вашей точки зрения, я имею в виду, что мне нужен способ немедленно получить отображаемый в данный момент экземпляр фрагмента, а не итеративно проверять все фрагменты, а затем решать, какой фрагмент теперь отображается на экране. - person Leem.fin; 15.02.2012

Что ж, этот вопрос получил много просмотров и внимания, но все же не содержал самого простого решения с моей стороны - использовать getFragments ().

            List fragments = getSupportFragmentManager().getFragments();
            mCurrentFragment = fragments.get(fragments.size() - 1);
person Nativ    schedule 16.05.2016
comment
К сожалению, это не всегда так, getSupportFragmentManager().getFragments() возвращает вам список, но он может содержать нулевые значения, если последний фрагмент только что был извлечен из backstack. Eq: Если вы проверите свой путь внутри метода onBackStackChanged() и вызовете где-нибудь popBackStack(), то mCurrentFragment будет null. - person Stumi; 15.02.2017
comment
@Stumi Спасибо за эту информацию. Да, звучит как одна из многих странных проблем жизненного цикла Android. - person Nativ; 28.03.2019

Если вы используете AndroidX Navigation:

val currentFragment = findNavController(R.id.your_navhost)?.currentDestination

Для получения дополнительной информации об этом компоненте навигации: https://developer.android.com/guide/navigation/navigation-getting-started

person Cory Roy    schedule 10.03.2020
comment
Это не компилируется - person IgorGanapolsky; 17.04.2020
comment
Он будет компилироваться только в том случае, если вы правильно настроили навигацию AndroidX и каким-то образом назвали свой navHost your_navhost. - person Cory Roy; 20.04.2020

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

public String getCurrentFragment(){
     return activity.getSupportFragmentManager().findFragmentById(R.id.content_frame).getClass().getSimpleName();
}

Использование:

Log.d(TAG, getCurrentFragment());

Выходы:

D/MainActivity: FragOne
person Mr L    schedule 27.05.2018

Немного поздно, но для всех, кому интересно: если вы знаете индекс нужного фрагмента в FragmentManager, просто получите ссылку на него и проверьте функцию isMenuVisible ()! здесь :

getSupportFragmentManager().getFragments().get(0).isMenuVisible()

Если true Это видно пользователю и так далее!

person MohammadReza    schedule 27.06.2014
comment
Как ни странно, это было единственное решение, указанное здесь, которое сработало для меня. В то же время несколько фрагментов могут иметь isVisible() == true, getView() != null. Плюс в моем коде getBackStackEntryCount всегда равен нулю. Несмотря на то, что я не использую меню, isMenuVisible() пока единственный дискриминант, который, кажется, надежно указывает на текущий «активный» фрагмент. ты - person parvus; 10.03.2015

Если вы попали сюда и используете Kotlin:

var fragment = supportFragmentManager.findFragmentById(R.id.fragment_container)

R.id.fragment_container - это id, где fragment представлены на своих activity

Или, если вам нужно более приятное решение:

supportFragmentManager.findFragmentById(R.id.content_main)?.let {
    // the fragment exists

    if (it is FooFragment) {
        // The presented fragment is FooFragment type
    }
}
person pableiros    schedule 13.11.2018

В SupportFragmentManager есть метод под названием findFragmentById(). Я использую его в контейнере активности, например:

public Fragment currentFragment(){
    return getSupportFragmentManager().findFragmentById(R.id.activity_newsfeed_frame);
}

Вот как получить свой текущий Fragment. Если у вас есть пользовательский Fragment и вам нужно проверить, что это Fragment, я обычно использую instanceof:

if (currentFragment() instanceof MyFrag){
    // Do something here
}
person Kevin Murvie    schedule 10.03.2017

Вдохновленный ответом Тайни, вот мои два цента. Немного изменен по сравнению с большинством других реализаций.

private Fragment getCurrentFragment() {
    FragmentManager fragmentManager = myActivity.getSupportFragmentManager();
    int stackCount = fragmentManager.getBackStackEntryCount();
    if( fragmentManager.getFragments() != null ) return fragmentManager.getFragments().get( stackCount > 0 ? stackCount-1 : stackCount );
    else return null;
}

Замените "myActivity" на «это», если это ваша текущая деятельность, или используйте ссылку на вашу деятельность.

person E Malik    schedule 14.06.2016

Это простой способ получить текущий фрагмент ..

getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
  @Override public void onBackStackChanged() {
    currentFragment = fragmentManager.findFragmentById(R.id.content);
    if (currentFragment !=  null && (currentFragment instanceof LoginScreenFragment)) {
      logout.setVisibility(View.GONE);
    } else {
      logout.setVisibility(View.VISIBLE);
    }
  }
});
person lallu Sukendh    schedule 08.09.2017

Ознакомьтесь с этим решением. Мне удалось получить текущий фрагмент.

if(getSupportFragmentManager().getBackStackEntryCount() > 0){
        android.support.v4.app.Fragment f = 
         getSupportFragmentManager().findFragmentById(R.id.fragment_container);
        if(f instanceof ProfileFragment){
            Log.d(TAG, "Profile Fragment");
        }else if(f instanceof SavedLocationsFragment){
            Log.d(TAG, "SavedLocations Fragment");
        }else if(f instanceof AddLocationFragment){
            Log.d(TAG, "Add Locations Fragment");
        }
person Haroon khan    schedule 27.09.2018

это так просто, не так уж много кода нужно писать yourFragment.isAdded() или yourFragment.isVisible();

Я предпочитаю isAdded (), оба из них возвращают логическое значение, используйте его в условии if и должны инициализировать свой фрагмент в onCreate (), иначе вы получите исключение с нулевой точкой.

person Saddan    schedule 20.10.2019
comment
Добро пожаловать в SO! Когда вы публикуете ответ, даже если он правильный, попробуйте его немного прокомментировать. В этом случае, с другим ответом 41, вы должны раскрыть плюсы и минусы вашего P.O.V. - person David García Bodego; 20.10.2019
comment
Спасибо, Дэвид, я ценю ваше предложение - person Saddan; 20.10.2019

Ответ Сева работает, когда вы нажимаете кнопку "Назад" или иным образом меняете стек назад.

Но я сделал что-то немного другое. У меня есть настройка прослушивателя изменений backstack на базовом фрагменте и его производных фрагментах, и этот код находится в прослушивателе:

Fragment f = getActivity().getSupportFragmentManager().findFragmentById(R.id.container);

if (f.getClass().equals(getClass())) {
    // On back button, or popBackStack(),
    // the fragment that's becoming visible executes here,
    // but not the one being popped, or others on the back stack

    // So, for my case, I can change action bar bg color per fragment
}
person MCLLC    schedule 12.06.2015

Простой способ сделать это:

Fragment fr=getSupportFragmentManager().findFragmentById(R.id.fragment_container);
String fragmentName = fr.getClass().getSimpleName();
person Biplob Das    schedule 11.02.2020

Это работа для меня. Надеюсь, это кому-то поможет.

FragmentManager fragmentManager = this.getSupportFragmentManager();  
        String tag = fragmentManager
                    .getBackStackEntryAt(
                    fragmentManager
                    .getBackStackEntryCount() - 1)
                    .getName();
              Log.d("This is your Top Fragment name: ", ""+tag);
person Cüneyt    schedule 16.12.2014

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

findFragmentByID(R.id.container);

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

Следующий метод не работает. Он просто получает фрагмент с тегом. Не тратьте время на этот метод. Я уверен, что он его использует, но получить самую последнюю версию того же фрагмента - не один из них.

findFragmentByTag()
person Yasin Yaqoobi    schedule 29.10.2015

getSupportFragmentManager().findFragmentById(R.id.content_frame).getClass().getSimpleName();

Что ж, я думаю, это наиболее прямой ответ на этот вопрос. Надеюсь, это поможет.

person Abhishek    schedule 11.06.2019

Вы можете сделать это очень легко также с помощью URL-адреса в logcat, который перенаправит вас на исходный код текущего исходного кода фрагмента. Во-первых, вам нужно добавить OnBackStackChangedListener в активность хоста, например:

activity.getChildFragmentManager().addOnBackStackChangedListener(backStackListener);

И реализация OnBackStackChangedListener -

    public FragmentManager.OnBackStackChangedListener backStackListener = () -> {

    String simpleName = "";
    String stackName = getStackTopName().trim();

    if (Validator.isValid(stackName) && stackName.length() > 0) {

      simpleName = stackName.substring(Objects.requireNonNull(stackName).lastIndexOf('.') + 1).trim();

      List<Fragment >
       fragmentList = getChildFragmentManager().getFragments();
      Fragment myCurrentFragment;

      for (int i = 0; i < fragmentList.size(); i++) {
       myCurrentFragment= fragmentList.get(i);
       if (myCurrentFragment.getClass().getSimpleName().equals(simpleName)) {
        //Now you get the current displaying fragment assigned in myCurrentFragment.
        break;
       }
       myFragment = null;
      }
     }


     //The code below is for the source code redirectable logcat which would be optional for you.
     StackTraceElement stackTraceElement = new StackTraceElement(simpleName, "", simpleName + ".java", 50);
     String fileName = stackTraceElement.getFileName();
     if (fileName == null) fileName = "";
     final String info = "Current Fragment is:" + "(" + fileName + ":" +
     stackTraceElement.getLineNumber() + ")";
     Log.d("now", info + "\n\n");
    };

А метод getStackTopName () -

public String getStackTopName() {
    FragmentManager.BackStackEntry backEntry = null;
    FragmentManager fragmentManager = getChildFragmentManager();
    if (fragmentManager != null) {
        if (getChildFragmentManager().getBackStackEntryCount() > 0)
            backEntry = getChildFragmentManager().getBackStackEntryAt(
                    getChildFragmentManager().getBackStackEntryCount() - 1
            );
    }
    return backEntry != null ? backEntry.getName() : null;
}
person Gk Mohammad Emon    schedule 09.12.2019

Ни один из 30 приведенных выше ответов не помог мне полностью. Но вот ответ, который сработал:

Используя Kotlin, при использовании компонента навигации:

fun currentVisibleFragment(): Fragment? {
    return supportFragmentManager.fragments.first()?.getChildFragmentManager()?.getFragments()?.get(0)
}
person coolcool1994    schedule 03.05.2020

В случае прокрученных фрагментов, когда вы используете экземпляр класса ViewPager, предположим, что mVeiwPager, вы можете вызвать mViewPager.getCurrentItem () для получения текущего номера int фрагмента.

в MainLayout.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical"
    tools:context="unidesign.photo360.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="false"
        android:theme="@style/AppTheme.AppBarOverlay"
        app:expanded="false">

        <android.support.v7.widget.Toolbar
            android:id="@+id/main_activity_toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            app:popupTheme="@style/AppTheme.PopupOverlay"
            app:title="@string/app_name">

        </android.support.v7.widget.Toolbar>

    </android.support.design.widget.AppBarLayout>


    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    </android.support.v4.view.ViewPager>
    
</android.support.design.widget.CoordinatorLayout>

в MainActivity.kt

class MainActivity : AppCompatActivity() {
    
        lateinit var mViewPager: ViewPager
        lateinit var pageAdapter: PageAdapter
        
//      ...
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            
            pageAdapter = PageAdapter(supportFragmentManager)
            mViewPager = findViewById(R.id.view_pager)
//          ...
            }
            
        override fun onResume() {
          super.onResume()
          var currentFragment = pageAdapter.getItem(mViewPager.currentItem)
//         ...
          }

person Andrei Radchenko    schedule 05.11.2017

Я обнаружил, что findFragmentByTag не так уж и удобен. Если у вас есть String currentFragmentTag в вашем Activity или родительском Fragment, вам нужно сохранить его в onSaveInstanceState и восстановить в onCreate. Даже если вы это сделаете, когда Activity воссоздается, onAttachFragment будет вызываться перед onCreate, поэтому вы не можете использовать currentFragmentTag в onAttachFragment (например, обновить некоторые представления на основе currentFragmentTag), потому что он может еще не восстановлен.

Я использую следующий код:

Fragment getCurrentFragment() {
    List<Fragment> fragments = getSupportFragmentManager().getFragments();
    if(fragments.isEmpty()) {
        return null;
    }
    return fragments.get(fragments.size()-1);
}

В документе FragmentManager говорится, что

Порядок фрагментов в списке - это порядок, в котором они были добавлены или прикреплены.

Когда вам нужно сделать что-то на основе текущего типа фрагмента, просто используйте getCurrentFragment() instance of MyFragment вместо currentFragmentTag.equals("my_fragment_tag").

Обратите внимание, что getCurrentFragment() в onAttachFragment получит не прикрепленный Fragment, а предыдущий прикрепленный.

person Jeffrey Chen    schedule 16.09.2018

Мне пришлось сделать это совсем недавно, и ни один из ответов здесь не подходил для этого сценария.

Если вы уверены, что будет виден только один фрагмент (в полноэкранном режиме), вы действительно хотите найти то, что находится наверху backstack. Например, как Kotlin для Fragment:

import androidx.fragment.app.Fragment

fun Fragment.setVisibilityChangeListener(clazz: Class<out Fragment>, listener: (Boolean) -> Unit) {
    fragmentManager?.run {
        addOnBackStackChangedListener {
            val topFragmentTag = getBackStackEntryAt(backStackEntryCount - 1).name
            val topFragment = findFragmentByTag(topFragmentTag)
            listener(topFragment != null && topFragment::class.java == clazz)
        }
    }
}

И используйте это так:

class MyFragment: Fragment {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        setVisibilityChangeListener(this::class.java) { visible -> 
            // Do stuff
        }
    }
}
person Mikel Pascual    schedule 13.03.2019

Вот решение Kotlin:

if ( this.getSupportFragmentManager().getBackStackEntryCount()>0 ) {
    var fgmt = this.getSupportFragmentManager().fragments[this.getSupportFragmentManager().getBackStackEntryCount()-1]
    if( fgmt is FgmtClassName ) {
        (fgmt as FgmtClassName).doSth()
    }
}

Упрощенный способ:

with ( this.getSupportFragmentManager() ) {
    if ( getBackStackEntryCount()>0 ) {
        var fgmt = fragments[getBackStackEntryCount()-1]
        if ( fgmt is FgmtClassName ) {
            (fgmt as FgmtClassName).doSth()
        }
    }
}
person anamkin    schedule 16.09.2019
comment
Попробуйте перемещаться между фрагментами и нажмите назад, приложение вылетит! - person Kishan Solanki; 26.08.2020

Если вы используете библиотеку Jetpack Navigation:

val currentFragment = defaultNavigator.currentDestination

person IgorGanapolsky    schedule 17.04.2020

Котлин безопаснее, чем здесь

supportFragmentManager.fragments.lastOrNull()?.let { currentFragment ->
               
      //Do something here
 }
person Oscar Emilio Perez Martinez    schedule 23.07.2020
comment
Я не уверен, но, может быть, для получения отображаемого в данный момент фрагмента следует использовать firstOrNull( ) вместо lastOrNull( )? - person Michael Abyzov; 15.10.2020

В основном действии метод onAttachFragment(Fragment fragment) вызывается, когда к действию присоединяется новый фрагмент. В этом методе вы можете получить экземпляр текущего фрагмента. Однако метод onAttachFragment(Fragment fragment) не вызывается, когда фрагмент извлекается из заднего стека, то есть когда нажимается кнопка возврата, чтобы поместить верхний фрагмент на вершину стека. Я все еще ищу метод обратного вызова, который запускается в основном действии, когда фрагмент становится видимым внутри действия.

person ufdeveloper    schedule 16.04.2013
comment
так близко! :-) - person Blundell; 22.01.2020
comment
Используем библиотеку Jetpack Navigation - person IgorGanapolsky; 17.04.2020

Я должен был сделать это совсем недавно

public Fragment getCurrentFragment() {
     return fragmentManager.findFragmentById(R.id.container);
}

и, наконец, я получил последний фрагмент на этом контейнере.

person Alireza Haji gholamreza    schedule 31.01.2021

Это должно сработать -

val visibleFragment = supportFragmentManager.fragments.findLast { fgm -> fgm.isVisible }
Timber.d("backStackIterator: visibleFragment: $visibleFragment")
person Anoop M Maddasseri    schedule 16.06.2021

Возможно, самый простой способ:

public MyFragment getVisibleFragment(){
    FragmentManager fragmentManager = MainActivity.this.getSupportFragmentManager();
    List<Fragment> fragments = fragmentManager.getFragments();
    for(Fragment fragment : fragments){
        if(fragment != null && fragment.getUserVisibleHint())
            return (MyFragment)fragment;
    }
    return null;
}

Это сработало для меня

person madx    schedule 07.06.2014

Использование шины событий (например, Otto, EventBus или RxJava Bus) особенно удобен в таких ситуациях.

Хотя этот подход не обязательно передает вам видимый в данный момент фрагмент как объект (хотя это тоже можно сделать, но это приводит к более длинной цепочке вызовов), он позволяет выполнять действия с видимым в данный момент фрагментом (обычно это то, что вы хотите знать текущий видимый фрагмент).

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

все видимые фрагменты, зарегистрированные на шине, выполнят необходимое действие.

person Kaushik Gopal    schedule 15.07.2015
comment
не могли бы вы объяснить более подробно? - person monad98; 26.01.2016
comment
Как мы можем использовать Eventbus в этом сценарии? Не могли бы вы поделиться одним примером. - person malli; 04.01.2018
comment
Это не сработает, если вы хотите вернуть значение - person TheRealChx101; 14.09.2019

Я столкнулся с аналогичной проблемой, когда хотел узнать, какой фрагмент отображался последним при нажатии клавиши возврата. Я использовал очень простое решение, которое мне помогло. Каждый раз, когда я открываю фрагмент, в методе onCreate () я устанавливаю переменную в своем синглтоне (замените myFragment на имя вашего фрагмента)

MySingleton.currentFragment = myFragment.class;

Переменная объявлена ​​в синглтоне как

public static Class currentFragment = null; 

Затем в onBackPressed () я проверяю

    if (MySingleton.currentFragment == myFragment.class){
        // do something
        return;
    }
    super.onBackPressed();

Обязательно вызовите super.onBackPressed (); после «возврата», иначе приложение обработает клавишу возврата, что в моем случае привело к завершению работы приложения.

person Zvi    schedule 22.08.2015

Немного странно, но я посмотрел на FragmentManager $ FragmentManagerImpl, и у меня работает следующее:

public static Fragment getActiveFragment(Activity activity, int index)
{
    Bundle bundle = new Bundle();
    String key = "i";
    bundle.putInt(key,index);
    Fragment fragment=null;
    try
    {
        fragment = activity.getFragmentManager().getFragment(bundle, key);
    } catch(Exception e){}
    return fragment;
}

чтобы получить первый активный фрагмент, используйте 0 в качестве индекса

person Hans    schedule 21.09.2015

public Fragment getVisibleFragment() {
    FragmentManager fragmentManager = getSupportFragmentManager();
    List<Fragment> fragments = fragmentManager.getFragments();
    if(fragments != null) {
        for (Fragment fragment : fragments) {
            if (fragment != null && fragment.isVisible())
                return fragment;
        }
    }
    return null;
}

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

Возвращаемый фрагмент можно сравнить с фрагментом, который вы хотите поместить в стек.

person Richard Olthuis    schedule 06.10.2015

Пожалуйста, попробуйте этот метод .....

private Fragment getCurrentFragment(){
    FragmentManager fragmentManager = getSupportFragmentManager();
    String fragmentTag = fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount() - 1).getName();
    Fragment currentFragment = getSupportFragmentManager()
.findFragmentByTag(fragmentTag);
    return currentFragment;
}
person Manmohan Soni    schedule 27.10.2015

Вы можете получить текущий фрагмент, используя следующий код

FragmentClass f = (FragmentClass)viewPager.getAdapter().instantiateItem(viewPager, viewPager.getCurrentItem());
person Devendra Kulkarni    schedule 06.12.2015

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

public Fragment selectedFragment;
public void changeFragment(Fragment newFragment){
    FragmentManager fragMgr = getSupportFragmentManager();
    FragmentTransaction fragTrans = fragMgr.beginTransaction();
    fragTrans.replace(android.R.id.content, newFragment);
    fragTrans.addToBackStack(null);
    fragTrans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
    fragTrans.commit();
    //here you update the variable
    selectedFragment = newFragment;
}

тогда вы можете использовать selectedFragment где угодно

person whd.nsr    schedule 09.12.2015
comment
Ага. А про лечение Бэка вы не забыли? - person user2413972; 01.04.2016

Здравствуйте, я знаю, что это очень старая проблема, но я хотел бы поделиться своим собственным решением ..

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

public class MyHelperClass{

    private static ArrayList<Fragment> listFragment = new ArrayList<>();

    public static void addFragment(Fragment f){
        if(!existFragment(f)) {
            listFragment.add(f);
        }
    }
    public static void removeFragment(){
        if(listFragment.size()>0)
            listFragment.remove(listFragment.size()-1);
    }
    public static Fragment getCurrentFragment(){
        return listFragment.get(listFragment.size()-1);
    }
    public static int sizeFragments(){
        return listFragment.size();
    }
    private static Boolean existFragment(Fragment f){
        Boolean ret = false;
        for(Fragment fragment : listFragment){
            if (fragment.getClass() == f.getClass()){
                ret = true;
            }
        }
        return ret;
    }

И в основном Activity я переопределяю метод onAttachFragment

@Override
public void onAttachFragment(Fragment f) {
    super.onAttachFragment(f);

    MyHelperClass.addFragment(f);
}

а также я переопределяю метод onBackPressed:

@Override
public void onBackPressed() {
        General.removeFragment();
        if(General.sizeFragments()>0){
            Fragment fragment = null;
            Class fragmentClass = General.getCurrentFragment().getClass();

            try {
                fragment = (Fragment) fragmentClass.newInstance();
                fragment.setArguments(General.getCurrentFragment().getArguments());
            } catch (Exception e) {
                e.printStackTrace();
            }

            fragmentManager.beginTransaction().replace(R.id.flContent, fragment).commit();
        }else{
            super.onBackPressed();
        }
}

таким образом вы в любое время можете получить активный фрагмент с помощью MyHelperClass.getCurrentFragment ()

Я надеюсь, что это будет полезно для всех

С уважением

person Ruben Flores    schedule 27.02.2016

ну, я думаю, вы хотите увидеть, в каком фрагменте вы находитесь, я думаю, есть решение, которое я не думаю, что оно лучшее, но оно работает Во-первых, вообще


вы должны создать свой родительский фрагмент, который расширяет фрагмент


public class Fragment2 extends Fragment {
    private static position;
    public static int getPosition() {
        return position;
    }

    public static void setPosition(int position) {
        FragmentSecondParent.position = position;
    }
}

Второй

вы должны расширять его в каждом фрагменте и при каждой записи в onCreateView

setPosition(//your fragmentposition here)

Третий


где вы хотите получить текущий фрагмент, вы должны


напиши это

Fragment2 fragment= (Fragment2) getSupportFragmentManager()
    .findFragmentById(R.id.fragment_status);

int position = fragment.getPosition();
if(//position condition)
{
    //your code here
}
person Farido mastr    schedule 27.03.2017

это лучший способ:

       android.app.Fragment currentFragment=getFragmentManager().findFragmentById(R.id.main_container);
            if(currentFragment!=null)
            {
                String[] currentFragmentName = currentFragment.toString().split("\\{");
                if (currentFragmentName[0].toString().equalsIgnoreCase("HomeSubjectFragment"))
                {
                    fragment = new HomeStagesFragment();
                    tx = getSupportFragmentManager().beginTransaction();
                    tx.replace(R.id.main_container, fragment);
                    tx.addToBackStack(null);
                    tx.commit();
                }
                else if(currentFragmentName[0].toString().equalsIgnoreCase("HomeStagesFragment"))
                {
                    new AlertDialog.Builder(this)
                            .setMessage("Are you sure you want to exit?")
                            .setCancelable(false)
                            .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int id) {
                                    finish();
                                }
                            })
                            .setNegativeButton("No", null)
                            .show();
                }

            }

не забудьте указать это в заголовке:

private Fragment fragment;
FragmentTransaction tx;
person Osama Ibrahim    schedule 12.07.2017

Если вы используете библиотеку поддержки v13, эта проблема устранена, и вам следует просто переопределить:

@Override
public void setUserVisibleHint(boolean isVisibleToUser)
{
    // TODO Auto-generated method stub
    super.setUserVisibleHint(isVisibleToUser);
}

Дело в том, что вы не можете смешивать их, потому что фрагмент несовместим с классом фрагментов версии 4.

Если это не так и вы используете библиотеку поддержки V4, переопределите метод setPrimaryItem для своего FragmentStatePagerAdapter.

Я использовал это для обновления названия Actionbat в больших списках.

person Mashiah    schedule 15.10.2013

Я тоже придерживался этой точки зрения. В конце концов я просто объявил массив фрагментов:

private static PlaceholderFragment[] arrFrg;

(в моем случае это PlaceholderFragment) и упаковал все эти Fragemnts в этот массив без тегов :)

        public static PlaceholderFragment newInstance(int sectionNumber) {
            final PlaceholderFragment fragment = new PlaceholderFragment();
            Bundle args = new Bundle();
            args.putInt(ARG_SECTION_NUMBER, sectionNumber);
            fragment.setArguments(args);
            arrFrg[sectionNumber] = fragment;

            return fragment;
}

Затем вы можете легко получить доступ к текущему отображаемому фрагменту:

arrFrg[mViewPager.getCurrentItem()];

Я понимаю, это, наверное, не лучшее решение, но у меня оно отлично работает :)

person Fellow7000    schedule 13.06.2018

Если у вас есть вложенные фрагменты, например страницы просмотра внутри страниц просмотра и т. Д., И вы хотите получить все вложенные фрагменты.

Спасибо и любезно предоставил ответ Мэтта Момбреа, немного измененную версию.

private List<Fragment> getVisibleFragments(List<Fragment> searchFragments, List<Fragment> visibleFragments) {
    if (searchFragments != null && searchFragments.size() > 0) {
        for (Fragment fragment : searchFragments) {
            List<Fragment> nestedFragments = new ArrayList<>();
            List<Fragment> childFMFragments = fragment.getChildFragmentManager().getFragments();
            List<Fragment> fmFragments = fragment.getFragmentManager().getFragments();
            fmFragments.retainAll(childFMFragments);
            nestedFragments.addAll(childFMFragments);
            nestedFragments.addAll(fmFragments);
            getVisibleFragments(nestedFragments, visibleFragments);
            if (fragment != null && fragment.isVisible()) {
                visibleFragments.add(fragment);
            }
        }
    }
    return visibleFragments;
}

А вот и использование:

List<Fragment> allVisibleFragments = getVisibleFragments(searchFragments, visibleFragments);

Например:

List<Fragment> visibleFragments = new ArrayList<>();
List<Fragment> searchFragments = MainActivity.this.getSupportFragmentManager().getFragments();
Toast.makeText(this, ""+getVisibleFragments(searchFragments, visibleFragments), Toast.LENGTH_LONG).show();
person 10101101    schedule 08.04.2019

если getFragmentManager () не работает, попробуйте использовать getSupportFragmentManager () и добавить тег во время загрузки фрагмента.

public void onBackPressed(){

    Fragment fragment=getSupportFragmentManager().findFragmentByTag(/*enter your tag*/);


    if(fragment!=null && fragment.isVisible())
    {
        //do your code here
    }
    else
    {
       //do your code here
    }

}
person Projit Roy    schedule 05.07.2019

для тех, кто ищет его в 2021 году, просто сделайте это: (R.id.fragment - это идентификатор вашего контейнера)

    val activeFragment  = this.supportFragmentManager.findFragmentById(R.id.fragment)?.childFragmentManager?.primaryNavigationFragment

    if (activeFragment is DetailFragment){
        (activeFragment as DetailFragment).onPermissionResult(permissionGranted)
    }
person Farhad957    schedule 26.02.2021