我在一个活动中有多个片段。在一个按钮点击我开始一个新的片段,添加到backstack。我自然希望调用当前Fragment的onPause()方法和新Fragment的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();
  }
}

我所期待的是,

单击按钮时,LoginFragment将被替换为 的HomeFragment、LoginFragment的onPause()和onResume() HomeFragment被调用 当按下back键时,HomeFragment弹出,LoginFragment弹出 以及HomeFragment的onPause()和LoginFragment的onResume() 被调用。

我得到的是,

单击按钮时,HomeFragment被正确替换 LoginFragment, HomeFragment的onResume()被调用,但onPause()被调用 LoginFragment从来不被调用。 当向后按,HomeFragment是正确弹出显示 LoginFragment, HomeFragment的onPause()被调用,但onResume() 的LoginFragment从未被调用。

这是正常行为吗?为什么LoginFragment的onResume()没有被调用,当我按下返回按钮。


当前回答

基于@Gor的回答,我在Kotlin中写了类似的东西。将此代码放在活动的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后提交事务

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

在你的代码中你应该替换

final FragmentManager mFragmentmanager =  getFragmentManager();

with

final FragmentManager mFragmentmanager =  getChildFragmentManager();

当一个片段出现/消失时,有两种可能的覆盖方法保证被调用。

Oncreateview /ondestroyview -当片段可见性改变时调用

Onpause /onresume -当应用程序被外部关闭或使用片段替换时调用

如果你想创建一个钩子,我这样做,你可以被通知,每当一个片段是关闭的,并捕捉任何一种情况,而不创建一个重复的调用,因为有时两者都可以被调用。

尝试扩展片段类,并在两个重写中添加一个布尔标志,这样就可以在不重复的情况下捕获open和close

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
            }

        }
    });

但如果有多个碎片可见,要小心

如果以XML格式添加片段,则不能动态地交换它们。发生的事情是他们过度,所以他们的事件不会像人们预期的那样爆发。这个问题在这个问题中有记载。FragmenManager replace使覆盖

将middle_fragment转换为FrameLayout,并像下面那样加载它,你的事件就会触发。

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