Фрагмент onResume () и onPause () не вызывается в backstack

У меня есть несколько фрагментов внутри деятельности. При нажатии кнопки я начинаю новый фрагмент, добавляя его в стопку. Естественно, я ожидал, что будет вызван метод onPause() текущего фрагмента и onResume() нового фрагмента. Ну этого не происходит.

LoginFragment.java

public class LoginFragment extends Fragment{
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      final View view  =   inflater.inflate(R.layout.login_fragment, container, false);
      final FragmentManager mFragmentmanager =  getFragmentManager();

      Button btnHome  = (Button)view.findViewById(R.id.home_btn);
      btnHome.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view){
           HomeFragment fragment    = new HomeFragment();
           FragmentTransaction ft2   =  mFragmentmanager.beginTransaction();
           ft2.setCustomAnimations(R.anim.slide_right, R.anim.slide_out_left
                    , R.anim.slide_left, R.anim.slide_out_right);
           ft2.replace(R.id.middle_fragment, fragment);
           ft2.addToBackStack(""); 
           ft2.commit();    
         }
      });
  }

  @Override
  public void onResume() {
     Log.e("DEBUG", "onResume of LoginFragment");
     super.onResume();
  }

  @Override
  public void onPause() {
    Log.e("DEBUG", "OnPause of loginFragment");
    super.onPause();
  }
}

HomeFragment.java

public class HomeFragment extends Fragment{
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
     final View view  =   inflater.inflate(R.layout.login_fragment, container, false);
  }

  @Override
  public void onResume() {
     Log.e("DEBUG", "onResume of HomeFragment");
     super.onResume();
  }

  @Override
  public void onPause() {
     Log.e("DEBUG", "OnPause of HomeFragment");
     super.onPause();
  }
}

Я ожидал, что

  1. При нажатии кнопки LoginFragment заменяется на HomeFragment, onPause() из LoginFragment и onResume() из HomeFragment вызывается
  2. При нажатии кнопки "Назад" появляется HomeFragment и отображается LoginFragment, а также onPause() из HomeFragment и onResume() из LoginFragment. называется.

Я получаю,

  1. При нажатии кнопки HomeFragment правильно заменяет LoginFragment, вызывается onResume () HomeFragment, но onPause () LoginFragment < / strong> никогда не вызывается.
  2. При обратном нажатии HomeFragment появляется правильно, показывая LoginFragment, вызывается onPause () из HomeFragment, но onResume () из LoginFragment никогда не вызывается.

Это нормальное поведение? Почему onResume() из LoginFragment не вызывается, когда я нажимаю кнопку "Назад".


person Krishnabhadra    schedule 04.07.2012    source источник
comment
Добавьте код активности, обрабатывающий фрагменты.   -  person blessenm    schedule 19.07.2012
comment
У меня проблема с образцом, при паузе не звонят, как вы ее решили,   -  person Sam    schedule 15.09.2012
comment
У меня была та же проблема, но я понял, что использую ft2.add (); вместо ft2.replace (). Другая причина может заключаться в том, что ваша деятельность сохраняет ссылку на фрагмент (добавляя его в коллекцию или присваивая его переменной класса)   -  person Friggles    schedule 26.02.2013
comment
Я с той же проблемой. Я заметил, что .replace () будет вызывать необходимые методы жизненного цикла, но по существу уничтожает фрагмент. Кроме того, onSaveInstanceState не вызывается. Таким образом, я не могу сохранить его состояние. Итак, мне нужно использовать add, но onResume / Pause не вызывается :(   -  person ariets    schedule 04.04.2013
comment
FWIW, мой опыт показывает, что фрагменты библиотеки поддержки вызывают onPause и onResume при нажатии / извлечении backstack, а встроенные фрагменты Android - нет. Пока не нашел подходящего обходного пути.   -  person benkc    schedule 22.12.2014
comment
зачем вы надуваете login_fragment в домашнем фрагменте? это опечатка?   -  person Maverick Meerkat    schedule 20.11.2018
comment
@DavidRefaeli Да, это была опечатка. Я попытался очистить кодовую базу (удалив некоторую неважную информацию) перед публикацией здесь. У меня больше нет доступа к этому коду (этот вопрос был задан 6 лет назад). Но я помню, что в тот день у меня это сработало.   -  person Krishnabhadra    schedule 20.11.2018


Ответы (19)


Фрагменты onResume() или onPause() будут вызываться только при вызове Activity onResume() или onPause(). Они тесно связаны с Activity.

Прочтите раздел Управление жизненным циклом фрагмента в этой статье.

person Sagar Waghmare    schedule 27.04.2013
comment
В статье говорится, что как только активность достигнет возобновленного состояния, вы можете свободно добавлять и удалять фрагменты активности. Таким образом, только когда действие находится в возобновленном состоянии, жизненный цикл фрагмента может измениться независимо. Означает ли это, что фрагмент onResume может быть вызван, даже если действие onResume не вызывается? - person v4r; 27.05.2014
comment
что касается собственных (не поддерживаемых) фрагментов в 4.4 (не уверен, верно ли это для более старых версий) onPause () и onResume () вызываются не только тогда, когда эти события происходят в действии, но, например, когда вы вызываете replace () или добавляете () / remove () при выполнении транзакции, поэтому этот ответ вводит в заблуждение, по крайней мере, для последних версий Android. - person Dmide; 25.11.2014
comment
Согласно этому документу, фрагмент должен быть фактически переведен в состояние остановки при замене в backstack. Но не только onPause и onResume не вызываются, но и onStop и onStart - или, если на то пошло, любые другие методы жизненного цикла. Так что руководство определенно вводит в заблуждение. - person benkc; 22.12.2014
comment
Хотя это не связано, но я нашел этот вопрос, когда искал свою проблему с вызовом onPause() после onSaveInstanceState(), а не до него. Это можно воспроизвести, если вы перейдете к другому дочернему элементу в моем FragmentStatePagerAdapter (скажем, вы переходите от дочернего элемента 0 к дочернему элементу 2, примечание к себе, это происходит потому, что дочерний элемент 0 уничтожается при открытии дочернего элемента 2) - person Sufian; 28.08.2015
comment
Не уверен, что вы имеете в виду. Вызов ft.replace должен запускать onPause (заменяемого фрагмента) и onResume (заменяющего фрагмента). Это делается независимо от какой-либо активности ... - person Maverick Meerkat; 20.11.2018
comment
Я могу подтвердить, что этого эффекта нет в последней версии Android 9.0. Фрагмент :: onResume () вызывается при появлении из backstack. Я также могу подтвердить, что у нас была эта проблема раньше, примерно 3/4 года назад. - person Qylin; 07.03.2019


Вот моя более надежная версия ответа Гора (использование fragments.size () ненадежно из-за того, что размер не уменьшается после извлечения фрагмента)

getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            if (getFragmentManager() != null) {

                Fragment topFrag = NavigationHelper.getCurrentTopFragment(getFragmentManager());

                if (topFrag != null) {
                    if (topFrag instanceof YourFragment) {
                        //This fragment is being shown. 
                    } else {
                        //Navigating away from this fragment. 
                    }
                }
            }
        }
    });

И метод getCurrentTopFragment:

public static Fragment getCurrentTopFragment(FragmentManager fm) {
    int stackCount = fm.getBackStackEntryCount();

    if (stackCount > 0) {
        FragmentManager.BackStackEntry backEntry = fm.getBackStackEntryAt(stackCount-1);
        return  fm.findFragmentByTag(backEntry.getName());
    } else {
        List<Fragment> fragments = fm.getFragments();
        if (fragments != null && fragments.size()>0) {
            for (Fragment f: fragments) {
                if (f != null && !f.isHidden()) {
                    return f;
                }
            }
        }
    }
    return null;
}
person aaronmarino    schedule 24.11.2016


getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            List<Fragment> fragments = getFragmentManager().getFragments();
            if (fragments.size() > 0 && fragments.get(fragments.size() - 1) instanceof YoureFragment){
                //todo if fragment visible
            } else {
                //todo if fragment invisible
            }

        }
    });

но будьте осторожны, если видно более одного фрагмента

person Gor    schedule 13.10.2016
comment
Спасибо, работает, но если виден только один фрагмент (значит, ViewPager с фрагментами будет ссылаться на его фрагменты). - person CoolMind; 02.08.2018

У меня есть код, очень похожий на ваш, и если он работает, onPause () и onResume (). При смене фрагмента эти функции активируются соответственно.

Код во фрагменте:

 @Override
public void onResume() {
    super.onResume();
    sensorManager.registerListener(this, proximidad, SensorManager.SENSOR_DELAY_NORMAL);
    sensorManager.registerListener(this, brillo, SensorManager.SENSOR_DELAY_NORMAL);
    Log.e("Frontales","resume");
}

@Override
public void onPause() {
    super.onPause();
    sensorManager.unregisterListener(this);
    Log.e("Frontales","Pause");

}

Журнал при смене фрагмента:

05-19 22:28:54.284 2371-2371/madi.cajaherramientas E/Frontales: resume
05-19 22:28:57.002 2371-2371/madi.cajaherramientas E/Frontales: Pause
05-19 22:28:58.697 2371-2371/madi.cajaherramientas E/Frontales: resume
05-19 22:29:00.840 2371-2371/madi.cajaherramientas E/Frontales: Pause
05-19 22:29:02.248 2371-2371/madi.cajaherramientas E/Frontales: resume
05-19 22:29:03.718 2371-2371/madi.cajaherramientas E/Frontales: Pause

Фрагмент onCreateView:

View rootView;
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    rootView = inflater.inflate(R.layout.activity_proximidad, container, false);
    ButterKnife.bind(this,rootView);
    inflar();
    setTextos();
    return rootView;
}

Действие, когда я возвращаюсь назад (в действии, в котором я загружаю фрагмент):

@Override
public void onBackPressed() {

    int count = getFragmentManager().getBackStackEntryCount();

    if (count == 0) {
        super.onBackPressed();

    } else {
        getFragmentManager().popBackStack();
    }

 }
person PepitoGrillo    schedule 19.05.2017
comment
Зависит от того, как вы меняете свой фрагмент. Если вы add это, а затем popBack, то onResume не будет вызываться. Возможно, у вас replacing фрагменты, а в popBack onResume срабатывает обратный вызов - person Farid; 10.03.2021

Я использую в своей деятельности - КОТЛИН

supportFragmentManager.addOnBackStackChangedListener {
                val f = supportFragmentManager.findFragmentById(R.id.fragment_container)

                if (f?.tag == "MyFragment")
                {
                    //doSomething
                }
            }
person Álvaro Agüero    schedule 10.05.2019

Что я делаю в дочернем фрагменте:

@Override
public void onDetach() {
   super.onDetach();
   ParentFragment pf = (ParentFragment) this.getParentFragment();
   pf.onResume();
}

А затем переопределите onResume на ParentFragment

person Guillermo De Juan    schedule 10.12.2017
comment
Никогда не следует вызывать методы жизненного цикла вручную, особенно друг в друге. - person breakline; 31.01.2018
comment
@breakline эта техника работает. У тебя есть другой способ? - person Vikash Parajuli; 06.03.2018
comment
Да, вам следует добавить свою собственную реализацию для вызова, потому что методы жизненного цикла также вызываются системой, и если вы вызываете методы жизненного цикла внутри друг друга таким образом, вы можете (и, скорее всего, вызовете) позже проблемы. - person breakline; 06.03.2018

Если вы добавляете фрагмент в XML, вы не можете менять местами их динамически. Происходит то, что они чересчур, поэтому события не срабатывают, как можно было бы ожидать. Проблема задокументирована в этом вопросе. Замена FragmenManager создает наложение

Превратите middle_fragment в FrameLayout и загрузите его, как показано ниже, и ваши события будут запущены.

getFragmentManager().beginTransation().
    add(R.id.middle_fragment, new MiddleFragment()).commit();
person Dustin    schedule 24.08.2015

Вы можете попробовать это,

Шаг 1. Переопределите метод Tabselected в своей деятельности

@Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    // When the given tab is selected, switch to the corresponding page in
    // the ViewPager.
    try {
    if(MyEventsFragment!=null && tab.getPosition()==3)
    {
        MyEvents.fragmentChanged();
    }
    }
    catch (Exception e)
    {

    }
    mViewPager.setCurrentItem(tab.getPosition());
}

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

public static void fragmentChanged()
{
    Toast.makeText(actvity, "Fragment Changed", Toast.LENGTH_SHORT).show();
}
person Manoj Kumar    schedule 20.01.2016

Основываясь на ответе @Gor, я написал подобное в Котлине. Поместите этот код в onCreate() действия. Работает для одного видимого фрагмента. Если у вас есть ViewPager с фрагментами, он вызовет фрагмент ViewPager, а не предыдущий.

supportFragmentManager.addOnBackStackChangedListener {
    supportFragmentManager.fragments.lastOrNull()?.onResume()
}

После прочтения https://medium.com/@elye.project/puzzle-fragment-stack-pop-cause-issue-on-toolbar-8b947c5c07c6 Я понял, что во многих ситуациях было бы лучше прикреплять новые фрагменты с помощью replace, а не add. Так что потребность в onResume в некоторых случаях отпадёт.

person CoolMind    schedule 20.07.2018

Хотя с другим кодом я столкнулся с той же проблемой, что и OP, потому что изначально я использовал

fm.beginTransaction()
            .add(R.id.fragment_container_main, fragment)
            .addToBackStack(null)
            .commit();

вместо того

fm.beginTransaction()
                .replace(R.id.fragment_container_main, fragment)
                .addToBackStack(null)
                .commit();

С «заменой» первый фрагмент воссоздается, когда вы возвращаетесь из второго фрагмента, и поэтому также вызывается onResume ().

person Greg Holst    schedule 26.11.2018
comment
На этот вопрос нет ответа, а что, если добавление необходимо для чьего-то дизайна ?! - person Farid; 08.03.2019

Вы просто не можете добавить фрагмент к фрагменту. Это должно произойти в FragmentActivity. Я предполагаю, что вы создаете LoginFragment в FragmentActivity, поэтому для того, чтобы это работало, вам нужно добавить HomeFragment через FragmentActivity при закрытии входа в систему.

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

person Nickolaus    schedule 07.11.2012
comment
Да, они находятся внутри активности фрагмента. - person Krishnabhadra; 08.11.2012
comment
если фрагменты добавляются динамически, вы можете добавить столько фрагментов, сколько хотите, к фрагменту, но не к тем, которые определены в теге xml ‹fragment› - person Illegal Argument; 12.06.2014
comment
Вложенные фрагменты теперь полностью поддерживаются AndroidX. - person aberaud; 21.05.2021

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

person AndroidGeek    schedule 16.07.2014

onPause() метод работает в классе активности, который вы можете использовать:

public void onDestroyView(){
super.onDestroyView    
}

с той же целью ..

person Vikrant Kaloniya    schedule 02.04.2017

Выполните следующие действия, и вы получите нужный ответ

1- Для обоих фрагментов создайте новый абстрактный родительский.
2- Добавьте собственный абстрактный метод, который должен быть реализован ими обоими.
3- Вызовите его из текущего экземпляра перед заменой вторым один.

person Mostafa Magdy    schedule 09.04.2018
comment
Как это помогает в ситуации, когда пользователь возвращается с фрагмента 2 на фрагмент 1? - person CoolMind; 20.07.2018

Вызов ft.replace должен запускать onPause (заменяемого фрагмента) и onResume (заменяющего фрагмента).

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

person Maverick Meerkat    schedule 20.11.2018
comment
На этот вопрос нет ответа, а что, если добавление необходимо для чьего-то дизайна ?! - person Farid; 08.03.2019

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

app:navGraph

создайте такой фрагмент (в Kotlin), а затем вызовите все функции жизненного цикла

val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.nav_host_fragment, fragment)
transaction.addToBackStack(null)
transaction.commit()
person Navid    schedule 01.06.2021

При создании транзакции фрагмента обязательно добавьте следующий код.

// Replace whatever is in the fragment_container view with this fragment, 
// and add the transaction to the back stack 
transaction.replace(R.id.fragment_container, newFragment); 
transaction.addToBackStack(null); 

Также убедитесь, что транзакция была зафиксирована после добавления ее в backstack.

person Mayur More    schedule 07.03.2013