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

у меня есть несколько фрагментов внутри активности. При нажатии кнопки я запускаю новый фрагмент, добавляя его в 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() of LoginFragment и onResume() of HomeFragment вызывается
  2. когда назад нажата,HomeFragment выскочил и LoginFragment is видел, и onPause() of HomeFragment и onResume() of LoginFragment вызывается.

что я получаю это,

  1. при нажатии кнопки , HomeFragment правильно заменить LoginFragment, onResume () of HomeFragment называется, но onPause() из LoginFragment никогда не вызывается.
  2. при нажатии назад,HomeFragment правильно появляются, чтобы выявить LoginFragment, onPause () of HomeFragment получает вызов, но onResume() из LoginFragment никогда не вызывается.

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

15 ответов


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

читать обработка раздела жизненного цикла фрагмента этой статьи.


  • так как вы использовали ft2.replace(), FragmentTransaction.remove() метод называется и Loginfragment будут удалены. См.этой. Так что onStop() of LoginFragment будет вызываться вместо onPause(). (Как новый фрагмент полностью заменяет старый).
  • но так как у вас также используется ft2.addtobackstack(), состояние Loginfragment будет сохранено в виде пакета и при нажатии кнопки "назад" из HomeFragment, onViewStateRestored() будет называться с последующим onStart() of LoginFragment. Так что в конце концов onResume() не назовешь.

Если вы действительно хотите заменить фрагмент В фрагмент вы должны использовать Вложенные Фрагменты.

в вашем коде вы должны заменить

final FragmentManager mFragmentmanager =  getFragmentManager();

С

final FragmentManager mFragmentmanager =  getChildFragmentManager();

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

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

у меня есть код очень похож на ваш, и если он работает 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");

}

Log при изменении фрагмента:

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

 }

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

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


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

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

getFragmentManager().beginTransation().
    add(R.id.middle_fragment, new MiddleFragment()).commit();

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
            }

        }
    });

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


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

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

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


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


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

Шаг 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();
}

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

public void onDestroyView(){
super.onDestroyView    
}

для той же цели..


выполните следующие действия, и вы получите необходимый ответ

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


на основе ответа @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 в некоторых случаях исчезнет.


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

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