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


196

활동 내부에 여러 조각이 있습니다. 버튼을 클릭하면 새 조각을 시작하여 백 스택에 추가합니다. 나는 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이 내가 뒤로 버튼을 누를 때 호출 안한다.


프래그먼트를 처리하는 활동 코드를 추가하십시오.
blessenm

나는 샘플 문제를 겪고 있는데, 멈추지 않을 때 호출되지 않았다. 어떻게 해결 했습니까?
Sam

나는 같은 문제가 있었지만 ft2.add (); ft2.replace () 대신. 활동이 프래그먼트에 대한 참조를 유지하는 경우 (컬렉션에 추가 또는 클래스 변수에 지정)
Friggles

3
같은 문제가 있습니다. .replace ()가 필요한 라이프 사이클 메소드를 호출하지만 본질적으로 조각을 파괴한다는 것을 알았습니다. 또한 onSaveInstanceState가 호출 되지 않습니다 . 따라서 상태를 유지할 수 없습니다. 따라서 add를 사용해야하지만 onResume / Pause는 호출되지 않습니다. (
ariets

FWIW, 내 경험은 지원 라이브러리 조각이 백 스택을 푸시 / 팝 할 때 onPause 및 onResume을 호출하지만 Android 내장 조각은 그렇지 않다는 것입니다. 아직 적절한 해결 방법을 찾지 못했습니다.
benkc December

답변:


187

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

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


1
이 기사에서는 "활동이 재개 된 상태에 도달하면 활동에 프래그먼트를 자유롭게 추가하고 제거 할 수 있습니다. 따라서 활동이 재개 된 상태 인 경우에만 프래그먼트의 라이프 사이클이 독립적으로 변경 될 수 있습니다"라고합니다. 이것은 onResume 활동이 호출되지 않더라도 onResume 조각을 호출 할 수 있음을 의미합니까?
v4r

3
4.4의 네이티브 (지원되지 않음) 조각 (이전 버전의 경우 사실인지 확실하지 않음) onPause () 및 onResume ()은 이러한 이벤트가 활동에서 발생할 때뿐만 아니라 replace () 또는 add를 호출 할 때 호출됩니다 () / remove () 트랜잭션을 수행하는 동안이 답변은 적어도 최신 Android 버전에서는 오해의 소지가 있습니다.
Dmide

19
이 문서에 따르면, 조각은 실제로 백 스택으로 교체 될 때 중지 상태로 이동해야합니다. 그러나 onPause 및 onResume이 호출되지 않을뿐만 아니라 onStop 및 onStart 또는 그 밖의 다른 수명주기 메소드도 호출되지 않습니다. 따라서 가이드는 확실히 잘못된 것입니다.
benkc

1
관련이 없지만 전보다 대신 onPause()호출되는 문제를 검색하는 동안이 질문을 발견 onSaveInstanceState()했습니다. 당신이 내 다른 아이에게 당신이 경우에 재현 할 수 있습니다 FragmentStatePagerAdapter(예를 들어, 아이 0에서 아이 2로 이동, 자아에주의하십시오, 이것은 아이 2가 열릴 때 아이 0이 파괴되기 때문에 발생합니다 )
Sufian

당신이 무슨 뜻인지 확실하지. ft.replace를 호출하면 onPause (교체 된 조각) 및 onResume (교체 조각)을 트리거해야합니다. 이것은 활동에 관계없이 수행됩니다 ...
David Refaeli

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

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

코드에서 대체해야합니다

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

@ breakline이 기술은 효과가 있습니다. 다른 방법이 있습니까?
Vikash Parajuli

예, 시스템에서 수명주기 메소드를 호출하기 때문에 호출 할 고유 구현을 추가해야합니다. 이와 같이 서로 수명주기 메소드를 호출하면 나중에 문제가 발생할 수 있습니다.
breakline

1

당신은 간단하게는 할 수없는 조각에 조각을 추가합니다. 이것은 FragmentActivity에서 발생해야합니다. FragmentActivity에서 LoginFragment를 작성한다고 가정 하므로이 작업을 수행하려면 로그인이 닫힐 때 FragmentActivity를 통해 HomeFragment를 추가해야합니다.

일반적인 요점은 각 Fragment를 FragmentManager에 추가하는 FragmentActivity 클래스가 필요하다는 것입니다. 이다 불가능 플래그먼트 클래스 내에서이 작업을 수행 할 수 있습니다.


예, 그들은 조각 활동 안에 있습니다.
Krishnabhadra

조각이 동적으로 추가되면 xml <fragment> tag에 정의 된 조각이 아닌 조각에 원하는만큼 조각을 추가 할 수 있습니다.
잘못된 인수

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

@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어떤 경우에는 필요 가 사라질 것입니다.


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에서 프래그먼트 1로 돌아갈 때 어떻게 도움이됩니까?
CoolMind

0

호출 ft.replace하면 onPause (교체 된 조각) 및 onResume (대체 조각)이 트리거되어야합니다.

귀하의 코드 login_fragment가 홈 조각에서 팽창 하고 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); 

또한 트랜잭션을 백 스택에 추가 한 후 커밋해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.