片段onResume()和onPause()在后台程序中未调用


194

我在一个活动中有多个片段。在一个按钮上,单击“我正在开始一个新片段”,将其添加到Backstack中。我自然希望可以调用onPause()当前Fragment和onResume()new Fragment 的方法。好吧,这没有发生。

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被替换为 HomeFragmentonPause() LoginFragmentonResume()HomeFragment被调用
  2. 当被压回,HomeFragment是POP操作并LoginFragment看到,和onPause()HomeFragmentonResume()LoginFragment 被调用。

我得到的是

  1. 单击按钮时,HomeFragment正确替换了 LoginFragment,onResume()的 HomeFragment被调用,但在onPause(的)LoginFragment永远不会被调用。
  2. 按下时,HomeFragment会正确弹出以显示 LoginFragment,将调用HomeFragment的 onPause(),但是会调用onResume() LoginFragment不会被调用。

这是正常行为吗?为什么当我按下“后退”按钮时onResume()LoginFragment没有被调用。


添加处理片段的活动代码。
blessenm

我遇到了示例问题,暂停时未接到电话,您如何解决此问题的,
山姆

我有同样的问题,但意识到我正在使用ft2.add(); 而不是ft2.replace()。唯一的其他原因是您的活动是否保留对该片段的引用(将其添加到集合中,或将其分配给类变量)
Friggles 2013年

3
我有同样的问题。我注意到.replace()将调用必要的生命周期方法,但实际上会破坏该片段。另外,不会调用onSaveInstanceState 。因此,我无法保持其状态。因此,我需要使用add,但是onResume / Pause不被调用:(
ariets 2013年

FWIW,我的经验是,支持库片段在推入/弹出后退堆栈时会调用onPause和onResume,但是Android内置片段不会。尚未找到合适的解决方法。
benkc 2014年

Answers:


185

仅当调用活动或时才调用片段onResume()或。他们紧密相连。onPause()onResume()onPause()Activity

阅读本文的“ 处理碎片生命周期”部分


1
在文章中说,“一旦活动达到恢复状态,就可以自由地向活动添加和删除片段。因此,只有在活动处于恢复状态时,片段的生命周期才能独立改变。” 这是否意味着即使未调用活动onResume也可以调用片段onResume?
v4r

3
对于4.4中的本机(不支持)片段(不确定旧版本是否适用),不仅会在活动中发生这些事件时调用onPause()和onResume(),例如,当您调用replace()或add ()/ remove()在执行交易时,因此,至少对于最新版本的Android,此答案具有误导性。
Dmide 2014年

19
根据该文档,当换出到堆栈中时,该片段实际上应该移至停止状态。但是不仅不会调用onPause和onResume,而且不会调用onStop和onStart,或者就此而言,也不会调用任何其他生命周期方法。因此,该指南绝对具有误导性。
benkc 2014年

1
虽然没有关系,但是我在寻找问题之前而不是onPause()之后被发现的时候发现了这个问题onSaveInstanceState()。这可以,如果你在被复制到不同的孩子我的FragmentStatePagerAdapter(说你从孩子0移动到孩子2,自我提醒,出现这种情况是因为孩子0被破坏孩子2打开时
苏菲安

不明白你的意思。调用ft.replace应该触发(替换片段的)onPause和(替换片段的)onResume。无论进行任何活动,都可以完成此操作……
David Refaeli,

20
  • 由于您已使用ft2.replace()FragmentTransaction.remove() 因此Loginfragment会调用方法,并且将被删除。参考这个。因此onStop()LoginFragment将调用而不是onPause()。(因为新片段完全替代了旧片段)。
  • 但由于您也已经使用过ft2.addtobackstack(),所以状态Loginfragment将被保存为捆绑销售商品,当您从中单击“后退”按钮时HomeFragmentonViewStateRestored()将被调用,后跟onStart()of LoginFragment。所以最终onResume()不会被调用。

1
onViewStateRestored如果有的话,将被呼叫setRetainInstance(true)
Farid

14

这是我的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. 
                    }
                }
            }
        }
    });

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

9

如果您真的想替换其他片段内的片段,则应使用嵌套片段

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

final FragmentManager mFragmentmanager =  getFragmentManager();

final FragmentManager mFragmentmanager =  getChildFragmentManager();

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

        }
    });

但请注意是否有多个片段可见


谢谢,它可以工作,但是如果只有一个片段可见(那么,ViewPager带有片段的将引用其片段)。
CoolMind

3

我有一个非常类似于您的代码,并且它可以在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");

}

更改片段时记录:

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

 }

2

我在子片段中做什么:

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

然后在ParentFragment上重写onResume


1
您永远不应手动调用生命周期方法,尤其是在彼此内部调用
断线

@breakline此技术有效。你还有其他办法吗?
Vikash Parajuli

是的,您应该添加自己的实现以进行调用,因为系统也会调用生命周期方法,并且如果这样彼此调用生命周期方法,则可能(并且很可能会)引起以后的问题。
突破线

1

您简单无法将片段添加到片段中。这需要在FragmentActivity中发生。我假设您是在FragmentActivity中创建LoginFragment,因此为了实现此目的,您需要在登录关闭时通过FragmentActivity添加HomeFragment。

总的来说,您需要一个FragmentActivity类,从中可以将每个片段添加到FragmentManager。这是不可能做到这一点片段类中。


是的,它们在片段活动中。
Krishnabhadra

如果片段是动态添加的,则可以向片段添加任意数量的片段,但不能添加到xml <fragment>标记中定义的片段
非法论点

1

如果以XML添加片段,则无法动态交换它们。发生的事情是它们过于过度,因此它们不会像人们期望的那样触发事件。该问题记录在此问题中。FragmenManager替换使覆盖

将middle_fragment转换为FrameLayout,然后像下面一样加载它,事件将触发。

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

1

你可以试试看

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

1

我在活动中使用-KOTLIN

supportFragmentManager.addOnBackStackChangedListener {
                val f = supportFragmentManager.findFragmentById(R.id.fragment_container)

                if (f?.tag == "MyFragment")
                {
                    //doSomething
                }
            }

0

片段必须始终嵌入活动中,并且片段的生命周期直接受到宿主活动的生命周期的影响。例如,活动被暂停时,其中的所有片段也被暂停;活动被销毁时,所有片段也被终止。



0

请按照以下步骤,您将获得所需的答案

1-对于这两个片段,创建一个新的抽象父对象。
2-添加一个自定义的抽象方法,这两个方法都应实现。
3-从当前实例调用它,然后替换为第二个实例。


当用户从片段2返回片段1时,它有什么帮助?
CoolMind

0

基于@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在某些情况下需求会消失。


0

呼唤 ft.replace应触发(替换片段的)onPause和(替换片段的)onResume。

我确实注意到您的代码login_fragment在home片段上膨胀了,并且也没有在onCreateView中返回视图。如果这些是错别字,您能否说明在活动中如何调用这些片段?


这不是答案,如果必须为某人的设计添加“添加”怎么办?
Farid

0

尽管使用不同的代码,但我遇到了与OP相同的问题,因为我最初使用

fm.beginTransaction()
            .add(R.id.fragment_container_main, fragment)
            .addToBackStack(null)
            .commit();

代替

fm.beginTransaction()
                .replace(R.id.fragment_container_main, fragment)
                .addToBackStack(null)
                .commit();

当您从第二个片段返回时,使用“替换”将重新创建第一个片段,因此也将调用onResume()。


这不是答案,如果必须为某人的设计添加“添加”怎么办?
Farid

-2

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.