Programing

백 스택에서 조각 onResume () 및 onPause ()가 호출되지 않습니다

crosscheck 2020. 5. 19. 21:29
반응형

백 스택에서 조각 onResume () 및 onPause ()가 호출되지 않습니다


활동 내부에 여러 조각이 있습니다. 버튼을 클릭하면 새 조각을 시작하여 백 스택에 추가합니다. 나는 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는 로 대체됩니다 HomeFragment , onPause()LoginFragmentonResume()HomeFragment 호출됩니다
  2. 다시 누르면 HomeFragment는 밖으로 poped하고 LoginFragment은 , 그리고 볼 onPause()HomeFragmentonResume()LoginFragment 호출됩니다.

내가 얻는 것은

  1. 버튼을 클릭하면, HomeFragment은 제대로 대체 LoginFragment , onResume ()를의 HomeFragment이 라고하지만, onPause ()의 LoginFragment가 호출되지 않습니다.
  2. 다시 버튼을 누르면, HomeFragment은 제대로 공개 보여주고있다 LoginFragment , onPause ()를의 HomeFragment가 호출되는하지만, onResume ()의 LoginFragment는 결코 호출되지됩니다.

이것이 정상적인 행동입니까? onResume()LoginFragment이 내가 뒤로 버튼을 누를 때 호출 안한다.


조각 onResume()또는 onPause()활동이 onResume()또는 호출 될 때만 onPause()호출됩니다. 그들은 밀접하게 연결되어 있습니다 Activity.

이 기사의 프래그먼트 라이프 사이클 처리 섹션을 읽으십시오 .


  • 당신이 사용하고 있기 때문에 ft2.replace(), FragmentTransaction.remove()메소드가 호출되고이 Loginfragment제거됩니다. 이것을 참조하십시오 . 그래서 onStop()LoginFragment대신 호출됩니다 onPause(). (새 조각이 이전 조각을 완전히 대체함에 따라).
  • 당신은 또한 사용했기 때문에 그러나 ft2.addtobackstack(),의 상태는 Loginfragment번들로 저장됩니다 때 당신은에서 버튼을 다시 클릭 HomeFragment, onViewStateRestored()다음에 호출됩니다 onStart()의를 LoginFragment. 결국에는 onResume()호출되지 않습니다.

다음은 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;
}

다른 조각 내부의 조각을 실제로 바꾸려면 Nested Fragments 를 사용해야합니다 .

코드에서 대체해야합니다

final FragmentManager mFragmentmanager =  getFragmentManager();

final FragmentManager mFragmentmanager =  getChildFragmentManager();

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
            }

        }
    });

하지만 둘 이상의 조각이 보이는 경우주의하십시오


나는 당신과 매우 비슷한 코드를 가지고 있으며 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");

}

Log when change of fragment:

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

Fragment 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;
}

Action when I pulse back (in the activity where I load the fragment):

@Override
public void onBackPressed() {

    int count = getFragmentManager().getBackStackEntryCount();

    if (count == 0) {
        super.onBackPressed();

    } else {
        getFragmentManager().popBackStack();
    }

 }

You simple can't add a fragment to a fragment. This needs to happen in the FragmentActivity. I assume you are creating the LoginFragment in a FragmentActivity, so in order to get this working you need to add the HomeFragment via the FragmentActivity when the login closes.

The general point is that you need a FragmentActivity class from where you add each Fragment to the FragmentManager. It is not possible to do this inside a Fragment class.


If you add the fragment in XML, you can't swap them dynamically. What happens is they overly, so they events don't fire as one would expect. The issue is documented in this question. FragmenManager replace makes overlay

Turn middle_fragment into a FrameLayout, and load it like below and your events will fire.

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

You can try this,

Step1: Override the Tabselected method in your activity

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

Step 2: Using static method do what you want in your fragment,

public static void fragmentChanged()
{
    Toast.makeText(actvity, "Fragment Changed", Toast.LENGTH_SHORT).show();
}

What i do in child fragment:

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

And then override onResume on ParentFragment


I use in my activity - KOTLIN

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

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

A fragment must always be embedded in an activity and the fragment's lifecycle is directly affected by the host activity's lifecycle. For example, when the activity is paused, so are all fragments in it, and when the activity is destroyed, so are all fragments


onPause() method works in activity class you can use:

public void onDestroyView(){
super.onDestroyView    
}

for same purpose..


Follow the below steps, and you shall get the needed answer

1- For both fragments, create a new abstract parent one.
2- Add a custom abstract method that should be implemented by both of them.
3- Call it from the current instance before replacing with the second one.


Based on the answer of @Gor I wrote similar in Kotlin. Place this code in onCreate() of an activity. It works for one fragment visible. If you have ViewPager with fragments, it will call ViewPager's fragment, not a previous one.

supportFragmentManager.addOnBackStackChangedListener {
    supportFragmentManager.fragments.lastOrNull()?.onResume()
}

After reading https://medium.com/@elye.project/puzzle-fragment-stack-pop-cause-issue-on-toolbar-8b947c5c07c6 I understood that it would be better in many situations to attach new fragments with replace, not add. So a need in onResume in some cases will disappear.


Calling ft.replace should trigger the onPause (of the replaced fragment) and onResume (of the replacing fragment).

I do notice that your code inflates login_fragment on the home fragment, and also doesn't return the views in the onCreateView. If these are typos, can you show how these fragments are being called from within your activity?


Although with different code, I experienced the same problem as the OP, because I originally used

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

instead of

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

With "replace" the first fragment gets recreated when you return from the second fragment and therefore onResume() is also called.


While creating a fragment transaction, make sure to add the following code.

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

Also make sure, to commit the transaction after adding it to backstack

참고URL : https://stackoverflow.com/questions/11326155/fragment-onresume-onpause-is-not-called-on-backstack

반응형