在backstack上不调用片段onResume()和onPause()

Kri*_*dra 183 android onresume android-fragments back-stack

我在一个活动中有多个片段.在按钮上单击我开始一个新片段,将其添加到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();
  }
}
Run Code Online (Sandbox Code Playgroud)

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();
  }
}
Run Code Online (Sandbox Code Playgroud)

我所期待的是,

  1. 当用户点击按钮,LoginFragment被替换为 HomeFragment,onPause()LoginFragmentonResume()HomeFragment被调用
  2. 当被压回,HomeFragment是POP操作并LoginFragment看到,和onPause()HomeFragmentonResume()LoginFragment 被调用.

我得到的是,

  1. 当用户点击按钮,HomeFragment正确更换 LoginFragment,的onResume()的HomeFragment被调用,但在onPause(的)LoginFragment永远不会被调用.
  2. 当按下回来,HomeFragment正确弹出透露 LoginFragment,在onPause()的HomeFragment被调用,但的onResume(的)LoginFragment不会被调用.

这是正常行为吗?为什么是onResume()LoginFragment当我按下后退按钮没有得到调用.

Sag*_*are 175

片段onResume()onPause()将仅在活动onResume()或被onPause()调用时被调用.他们紧紧联系在一起Activity.

阅读本文的处理片段生命周期部分.

  • 根据该文档,当交换到后台时,片段实际上应该被移动到停止状态.但不仅onPause和onResume没有被调用,onStop和onStart也不会 - 或者就此而言,任何其他生命周期方法.所以指南肯定是误导. (15认同)
  • 对于4.4中的本机(不支持)片段(不确定它是否适用于旧版本)onPause()和onResume()不仅在活动中发生这些事件时被调用,而且例如当您调用replace()或添加时()/ remove()在执行交易时,所以这个答案至少对Android的最新版本有误导性. (3认同)
  • 文章中说,“一旦Activity达到恢复状态,就可以自由地向该Activity添加和删除fragment。因此,只有当Activity处于恢复状态时,一个fragment的生命周期才能独立变化。” 这是否意味着即使未调用活动 onResume 也可以调用片段 onResume ? (2认同)
  • 虽然不相关,但我在搜索我的“onPause()”问题时发现了这个问题,该问题在“onSaveInstanceState()”之后而不是在它之前被调用。如果你在我的 `FragmentStatePagerAdapter` 中使用不同的孩子,这可以被复制(假设你从孩子 0 移动到孩子 2,**注意自我,发生这种情况是因为当孩子 2 打开时孩子 0 被销毁**) (2认同)

小智 19

  • 由于您已经使用过ft2.replace(),FragmentTransaction.remove() 因此调用方法并Loginfragment删除它.参考这个.所以onStop()LoginFragment将被调用,而不是onPause().(因为新片段完全取代旧片段).
  • 但是既然你已经使用了ft2.addtobackstack(),那么它的状态Loginfragment将被保存为一个包,当你点击后退按钮时HomeFragment, onViewStateRestored()将被调用,然后onStart()LoginFragment.所以最终onResume()不会被召唤.

  • 如果您有“setRetainInstance(true)”,则会调用“onViewStateRestored” (2认同)

aar*_*ino 11

这是我更强大的Gor的答案版本(使用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. 
                    }
                }
            }
        }
    });
Run Code Online (Sandbox Code Playgroud)

'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;
}
Run Code Online (Sandbox Code Playgroud)


Ber*_*rsh 9

如果你真的想要替换其他片段中的片段,你应该使用嵌套片段.

在您的代码中,您应该替换

final FragmentManager mFragmentmanager =  getFragmentManager();
Run Code Online (Sandbox Code Playgroud)

final FragmentManager mFragmentmanager =  getChildFragmentManager();
Run Code Online (Sandbox Code Playgroud)


小智 7

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
            }

        }
    });
Run Code Online (Sandbox Code Playgroud)

但如果有多个片段可见,请小心