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


当前回答

在创建片段事务时,请确保添加以下代码。

// 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后提交事务

其他回答

基于@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中的需求将会消失。

你可以试试这个,

第一步:在你的活动中覆盖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();
}

你不能简单地将一个片段添加到一个片段中。这需要在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()

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

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

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

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

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