web-dev-qa-db-ja.com

フラグメントonResume()およびonPause()はバックスタックで呼び出されません

アクティビティ内に複数のフラグメントがあります。ボタンをクリックして、新しいフラグメントを開始し、バックスタックに追加します。私は当然、現在のフラグメントの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();
  }
}

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. ボタンをクリックすると、LoginFragmentHomeFragmentonPause() ofLoginFragmentに置き換えられます、およびHomeFragmentonResume()が呼び出されます
  2. 戻るボタンを押すと、HomeFragmentがポップアウトされ、LoginFragmentが表示され、onPause() ofHomeFragmentLoginFragmentonResume()が呼び出されます。

私が得ているのは、

  1. ボタンをクリックすると、HomeFragmentが正しく置き換えられますLoginFragment、onResume()ofHomeFragmentが呼び出されますが、LoginFragmentのonPause()は呼び出されません。
  2. バックプレスすると、HomeFragmentが正しくポップしてLoginFragment、onPause()ofHomeFragmentが呼び出されますが、LoginFragmentのonResume()は呼び出されません。

これは通常の動作ですか? LoginFragmentonResume()が戻るボタンを押しても呼び出されないのはなぜですか。

177
Krishnabhadra

フラグメントonResume()またはonPause()は、Activities onResume()またはonPause()が呼び出されたときにのみ呼び出されます。それらはActivityと密接に関係しています。

この記事の「フラグメントのライフサイクル」セクションの処理 を読んでください。

160
Sagar Waghmare
  • ft2.replace()を使用したので、FragmentTransaction.remove()メソッドが呼び出され、Loginfragmentは削除されます。 this を参照してください。そのためonStop()の代わりにLoginFragmentonPause()が呼び出されます。 (新しいフラグメントが古いものを完全に置き換えるので)。
  • しかしft2.addtobackstack()も使っているので、Loginfragmentの状態はバンドルとして保存され、HomeFragmentから戻るボタンをクリックするとonViewStateRestored()が呼び出され、LoginFragmentonStart()が呼び出されます。そのため、最終的にonResume()は呼び出されません。
18
Gopal

これが私のより堅牢なバージョンのGorの答えです(fragment.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;
}
10
aaronmarino

本当に他のフラグメントの中にあるフラグメントを置き換えたい場合は、 Nested Fragments を使うべきです。

あなたのコードではあなたが置き換える必要があります

final FragmentManager mFragmentmanager =  getFragmentManager();

final FragmentManager mFragmentmanager =  getChildFragmentManager();
9
Bersh
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
            }

        }
    });

ただし、複数のフラグメントが表示されている場合は注意してください。

3
Gor

私はあなたのものと非常によく似たコードを持っていて、それが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
PepitoGrillo

これを試すことができます

ステップ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
Manoj Kumar

あなたは単純ですできませんフラグメントをフラグメントに追加します。これはFragmentActivityで発生する必要があります。私はあなたがFragmentActivityでLoginFragmentを作成していると仮定します、それでこれを働かせるためにはログインが閉じるときFragmentActivityを通してHomeFragmentを追加する必要があります。

一般的な点は、各FragmentをFragmentManagerに追加する場所からFragmentActivityクラスが必要なことです。 Fragmentクラスの中でこれを行うのは不可能です。

1
Nickolaus

XMLでフラグメントを追加した場合、それらを動的に交換することはできません。何が起こるかというと、彼らは過度にそうなっているので、彼らが期待するようにイベントは発生しません。問題はこの質問に文書化されています。 FragmenManagerの置き換えでオーバーレイが作成されます

Middle_fragmentをFrameLayoutに変えて、以下のようにロードするとあなたのイベントが発生します。

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

私は子フラグメントで何をしますか:

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

そしてParentFragmentのonResumeをオーバーライドします。

1

フラグメントは常にアクティビティに埋め込まれる必要があり、フラグメントのライフサイクルはホストアクティビティのライフサイクルによって直接影響を受けます。たとえば、アクティビティが一時停止されると、その中のすべてのフラグメントも消去され、アクティビティが破棄されると、すべてのフラグメントも消去されます。

0
Xar E Ahmer

onPause()メソッドはあなたが使うことができるアクティビティクラスで動作します:

public void onDestroyView(){
super.onDestroyView    
}

同じ目的のために。

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

"replace"を使用すると、2番目のフラグメントから戻ったときに最初のフラグメントが再作成されるため、onResume()も呼び出されます。

0
Greg Holst

ft.replaceを呼び出すと、(置き換えられたフラグメントの)onPauseと(置き換えられたフラグメントの)onResumeがトリガされます。

私はあなたのコードがhomeフラグメントのlogin_fragmentを膨らませること、そしてまたonCreateViewのビューを返さないことに気付きます。これらがタイプミスであるならば、あなたはこれらのフラグメントがあなたの活動の中からどのように呼ばれているかを示すことができますか?

0
David Refaeli

@ Gor の答えに基づいて、私はKotlinで同じように書いた。このコードをアクティビティのonCreate()に配置します。それは目に見える1つの断片のために働きます。フラグメント付きの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
CoolMind

以下のステップに従うと、あなたは必要な答えを得るでしょう

1 - 両方のフラグメントに対して、新しい抽象親を作成します。
2-両者によって実装されるべきであるカスタム抽象メソッドを追加する。
3- 2番目のインスタンスと置き換える前に、現在のインスタンスから呼び出します。

0
Mostafa Magdy

私は自分の活動に使っています - KOTLIN

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

                if (f?.tag == "MyFragment")
                {
                    //doSomething
                }
            }
0
Álvaro Agüero