フラグメントonResume()およびonPause()がバックスタックで呼び出されない


194

アクティビティ内に複数のフラグメントがあります。ボタンをクリックすると、新しいフラグメントが開始され、バックスタックに追加されます。私は当然onPause()、現在のFragmentとonResume()新しい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()LoginFragment、とonResume()HomeFragment呼び出されます
  2. バックが押された場合、HomeFragmentが出てポップされ及びLoginFragmentは、と見られているonPause()HomeFragmentonResume()LoginFragment 呼び出されます。

私が得ているのは、

  1. ボタンがクリックされると、HomeFragmentLoginFragmentを正しく置き換えている ため、HomeFragmentのonResume()が呼び出されますが、LoginFragmentのonPause()が呼び出されることはありません。
  2. BackFragmentを押すと、HomeFragmentが正しくポップして LoginFragmentが表示され、HomeFragmentのonPause()が呼び出されますが、LoginFragmentのonResume()は呼び出されません。

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


フラグメントを処理するアクティビティコードを追加します。
blessenm

私はサンプルの問題を抱えています、一時停止時に呼び出されません、これをどのように解決しましたか
Sam

同じ問題がありましたが、ft2.add()を使用していることに気付きました。ft2.replace()の代わりに。他の理由は、アクティビティがフラグメントへの参照を保持している(コレクションに追加する、またはクラス変数に割り当てる)場合です
Friggles

3
私も同じ問題を抱えています。.replace()が必要なライフサイクルメソッドを呼び出すことに気づきましたが、基本的にフラグメントを破棄します。また、onSaveInstanceStateは呼び出されません。そのため、その状態を維持できません。したがって、addを使用する必要がありますが、onResume / Pauseは呼び出されません:(
ariets

FWIW、私の経験では、サポートライブラリフラグメントは、バックスタックをプッシュ/ポップするときにonPauseおよびonResumeを呼び出しますが、Android組み込みフラグメントは呼び出しません。そのための適切な回避策はまだ見つかりません。
benkc 14

回答:


185

フラグメントonResume()またはonPause()は、アクティビティonResume()またはonPause()が呼び出されたときにのみ呼び出されます。これらはに密接に結合されていActivityます。

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


1
記事では、「アクティビティが再開状態になったら、自由にアクティビティにフラグメントを追加および削除できます。したがって、アクティビティが再開状態にある間のみ、フラグメントのライフサイクルを個別に変更できます。」これは、アクティビティonResumeが呼び出されなくてもフラグメントonResumeを呼び出すことができることを意味しますか?
v4r 2014年

3
4.4のネイティブ(サポートされていない)フラグメントについては(古いバージョンではtrueかどうかわからない)onPause()とonResume()は、アクティビティでこれらのイベントが発生したときだけでなく、たとえばreplace()またはaddを呼び出したときにも呼び出されます。 ()/ remove()トランザクションを実行している間、この回答は少なくとも最近のバージョンのAndroidでは誤解を招くものです。
Dmide 2014年

19
そのドキュメントによると、バックスタックにスワップアウトされると、フラグメントは実際には停止状態に移行するはずです。しかし、onPauseとonResumeが呼び出されないだけでなく、onStopとonStartも呼び出されません。つまり、他のライフサイクルメソッドも呼び出されません。そのため、ガイドは間違いなく誤解を招くものです。
benkc 14

1
関連はありませんが、前にではなくonPause()onSaveInstanceState()に呼び出されるという私の問題を検索しているときにこの質問を見つけました。これは、あなたが私の中で別の子供になった場合に再現できますFragmentStatePagerAdapter(たとえば、子供0から子供2に移動するとします。これは、子供2が開くと子供0が破壊されるため発生します
Sufian

よく分からない。ft.replaceを呼び出すと、(置換されたフラグメントの)onPauseと(置換されたフラグメントの)onResumeがトリガーされます。これは、アクティビティに関係なく行われます...
David Refaeli 2018年

20
  • を使用したのでft2.replace()FragmentTransaction.remove() メソッドが呼び出され、Loginfragmentが削除されます。こちらをご覧ください。だから、onStop()LoginFragment代わりに呼び出されますonPause()。(新しいフラグメントが古いフラグメントを完全に置き換えるため)。
  • しかし、あなたはまた、使用しておりますのでft2.addtobackstack()、状態はLoginfragmentバンドルとして保存され、あなたからボタンをクリックしたときに戻ってHomeFragmentonViewStateRestored()続く呼び出されますonStart()LoginFragment。したがって、最終的onResume()には呼び出されません。

1
onViewStateRestoredあなたが持っている場合に呼び出されますsetRetainInstance(true)
ファリド

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
            }

        }
    });

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


おかげで動作しますが、フラグメントが1つしか表示されない場合(フラグメントがある場合はViewPagerフラグメントを参照します)。
CoolMind 2018

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 2018年

はい、ライフサイクルメソッドはシステムによっても呼び出されるため、独自の実装を追加して呼び出す必要があります。ライフサイクルメソッドをこのように相互に呼び出すと、後で問題が発生する可能性があります(ほとんどの場合)。
ブレークライン2018年

1

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

一般的なポイントは、FragmentActivityクラスが必要であり、そこから各FragmentをFragmentManagerに追加します。これをFragmentクラス内で行うことはできません


はい、それらはフラグメントアクティビティ内にあります。
Krishnabhadra

フラグメントが動的に追加される場合、フラグメントに必要なだけフラグメントを追加できますが、xml <fragment>タグで定義されたフラグメントには追加できません
不正な引数

1

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

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

onPause() メソッドは、使用できるアクティビティクラスで機能します。

public void onDestroyView(){
super.onDestroyView    
}

同じ目的のために..


0

以下の手順に従ってください、そしてあなたは必要な答えを得ます

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


ユーザーがフラグメント2からフラグメント1に戻るときにどのように役立ちますか?
CoolMind 2018

0

@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

呼び出しft.replaceにより、(置換されたフラグメントの)onPauseと(置換されたフラグメントの)onResumeがトリガーされます。

私はあなたのコードlogin_fragmentがホームフラグメントを膨らませ、onCreateViewでビューを返さないことに気づきます。これらがタイプミスである場合、これらのフラグメントがアクティビティ内からどのように呼び出されているかを示すことができますか?


これは答えではありません。誰かのデザインに「追加」が必要な場合はどうなりますか?!
ファリド

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()も呼び出されます。


これは答えではありません。誰かのデザインに「追加」が必要な場合はどうなりますか?!
ファリド

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

また、トランザクションをバックスタックに追加した後にコミットすることも確認してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.