我在一个活动中有多个片段。在一个按钮点击我开始一个新的片段,添加到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()没有被调用,当我按下返回按钮。


当前回答

科特林

requireFragmentManager().addOnBackStackChangedListener {
            val fragments: List<Fragment> = requireFragmentManager().fragments
            if (fragments.isNotEmpty() && fragments[fragments.size - 1] is YOUR_FRAGMENT) {
                //todo if fragment visible
            } else {
                //todo if fragment invisible
            }
        }

其他回答

Since you have used ft2.replace(), FragmentTransaction.remove() method is called and the Loginfragment will be removed. Refer to this. So onStop() of LoginFragment will be called instead of onPause(). (As the new fragment completely replaces the old one). But since you have also used ft2.addtobackstack(), the state of the Loginfragment will be saved as a bundle and when you click back button from HomeFragment, onViewStateRestored() will be called followed by onStart() of LoginFragment. So eventually onResume() won't be called.

我在child fragment中做的事情:

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

然后在ParentFragment上覆盖onResume

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

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

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

你不能简单地将一个片段添加到一个片段中。这需要在FragmentActivity中发生。我假设你在一个FragmentActivity中创建LoginFragment,所以为了让这个工作,你需要在登录关闭时通过FragmentActivity添加HomeFragment。

一般来说,你需要一个FragmentActivity类,从那里你可以将每个Fragment添加到FragmentManager中。在Fragment类中不可能做到这一点。

对我来说,原因是使用navGraph在片段之间切换

app:navGraph

像这样创建片段(在Kotlin中),然后调用所有的生命周期函数

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