본문 바로가기
개발/안드로이드

Fragment LifeCycle 메소드 호출 순서

by darksilber 2015. 5. 5.
반응형

출처 - http://blog.naver.com/regako/220261214098

 

일반 액티비티와 프래그먼트액티비티의 생명주기 차이를 나타내는 플로우 다이어그램은

널리고 널렸으니 제쳐 두고, 


이번 포스트는 프래그먼트들을 더하거나(add) 갈아치울 때(replace) 등등의 경우에

각 프래그먼트들에 불리는 method들을 정리해봤다.


기본적으로 프래그먼트 액티비티(Main)가 있고, 여기에 2개의 프래그먼트(F1, F2)를 이리저리

해보면서 직접 로그로 찍어본 결과들이다.


- case 1: Main에 F1을 add로 추가한다.(fragmentManager.beginTransaction().add(id, F1, "f1").commit() - 이후 아래부터는 commit 명령  생략함)

Main onCreate

F1 onAttach

Main onAttachFragment

F1 onCreate

F1 onCreateView

F1 onViewCreated

F1 onActivityCreated

F1 onStart

Main onStart

Main onResume

F1 onResume 

Main onResumeFragments

Main onPostResume

* 특이 사항 : onStart는 F1,Main순으로 불리는데 onResume은 그 반대로 불린다.


- case 2: 위 상황에 이어서 back 키로 앱 종료

F1 onPause

Main onPause

F1 onStop

Main onStop

F1 onDestroyView

F1 onDestory

F1 onDetach

Main onDestroy


- case 3: case 1 상황에 이어서 F1을 F2로 replace(fragmentManager.beginTransaction().replace(id, F2, "f2"))

F1 onPause

F1 onStop

F1 onDestroyView

F1 onDestroy

F1 onDetach

F2 onAttach

Main onAttachFragment

F2 onCreate

F2 onCreateView

F2 onViewCreated

F2 onActivityCreated

F2 onStart

F2 onResume


- case 4 : case 1 상황에 이어서 F1을 remove하고  F2를 add(fragmentManager.beginTransaction().remove(F1).add(id,F2,"f2"))

*case 3과 동일. 애초에 replace가 remove+add이므로 당연한 결과라 할 수 있다.



----여기서 추가 조건. 

case 5 : Main에서 F1과 F2를 모두 더한 상태로 조건을 수정한다. add F1, add F2 하고 F2를 detach로 숨긴 상황이다.


- case 6 :  case 5 상황에 이어서 F1을 detach하고  F2를 attach(fragmentManager.beginTransaction().detach(F1).attach(F2))

F1 onPause

F1 onStop

F1 onDestoryView

F2 onCreateView

F2 onViewCreated

F2 onActivityCreated

F2 onStart

F2 onResume

* 특이사항 : remove, add와의 차이점은 onCreate,onAttach,onDetach,onDestroy가 불리지 않는다는 점이다.

헷갈리기 쉬운데 attach,detach를 사용할 때 오히려 onAttach,onDetach가 안 불리는 걸 주의하자.


- case 7: case 5 상황에 이어서 F1을 hide하고  F2를 show(fragmentManager.beginTransaction().hide(F1).show(F2))

* 아무 api도 호출되지 않음!

* 즉, 모든 fragment가 그냥 모습 그대로 살아있다는 얘기다. 각 프래그먼트들의 전환과 업데이트에 골치가 아플 때

메모리문제만 없으면 이게 제일 속시원한 방법이다.


----여기서 추가 조건.

일반적인 전환이 아니라 addToBackStack(null)을 이용해 스택을 쌓으면서 전환시키는 경우를 살펴본다.

스택을 쌓으며 전환하면 Back동작시에 자동으로 이전 프래그먼트를 보여주는 기능이 있다.


- case 8: 히스토리 스택에 쌓으면서 F1을 F2로 replace(replace(id,F2,"f2").addToBackStack(null))

F1 onPause

F1 onStop

F1 onDestoryView

F2 onAttach

Main onAttachFragment

F2 onCreate

F2 onCreateView

F2 onViewCreated

F2 onActivityCreated

F2 onStart

F2 onResume


- case 9: case 8 상황에서 back으로 F1 pop

F2 getView

F2 onPause

F2 onStop

F2 onDestroyView

F1 onCreateView

F1 onViewCreated

F1 onActivityCreated

F1 onStart

F1 onResume


- case 10: 히스토리 스택에 쌓으면서 F1 detach, F2  attach

F1 onPause

F1 onStop

F1 onDestoryView

F2 onCreateView

F2 onViewCreated

F2 onActivityCreated

F2 onStart

F2 onResume


- case 11: case 10 상황에서 back으로 F1 pop

F2 getView

F2 onPause

F2 onStop

F2 onDestroyView

F1 onCreateView

F1 onViewCreated

F1 onActivityCreated

F1 onStart

 

F1 onResume

* 특이 사항 : 위 4 경우를 보면, replace(=remove+add)와 detach, attach가 F2 onAttach빼고는 전부  동일하다.

스택에 쌓지 않는 경우에는 replace시에 기존 프래그먼트의 onDetach와 onDestroy가 불리는데, 위 경우에는

그런 게 불리지가 않아 detach, attach와 동일해진 것이다. 스택에 쌓으려면 보관을 해야되니 그렇게 하는 것이

당연할 수도 있겠다.


아 그리고 주의할 점.

FragmentManager는 변수로 빼도 되지만, 실제로 동작을 처리하는 FragmentTransaction은 매번 호출해줘야 한다.

즉 클래스의 멤버변수로 

private FragmentManager mFragmentManager=null;

을 선언해놓고 액티비티를 생성할 때 onCreate()에서

mFragmentManager = getSupportFragmentManager();

로 지정해서 여기저기서 사용할 수 있지만, FragmentTransaction은 저렇게 변수로 빼면 안된다.

이후 add,replace의 동작을 할 때는

mFragmentManager.beginTransation().add(blabla).commit();

와 같이 beginTransaction을 꼭 해주어야 함을 기억하자.

위의 모든 명령어의 마지막에는 반드시 commit을 해주는건 기본 상식이다.


번외 1.

FragmentManager는 FragmentActivity(Main)의 getSupportFragmentManager로 얻을 수가 있고,

하위 Fragment(F1)에서 getChildFragmentManager()로도 얻을 수가 있는데, 이 FragmentManager들은

서로 다른 매니저이다. 즉 다수의 프래그먼트매니저를 얻어와서 컨트롤할 수가 있다는 말인데 이런 사례가 있을 수 있겠다.

프래그먼트액티비티안에 4개의 프래그먼트들로 이루어진 탭이 있는데 이 각각의 탭을 전환할때는 Main의

매니저를 이용해 replace를 하고, 하나의 탭에서 히스토리를 쌓아가며 깊게 들어가는 시나리오가 있다면

그 깊게 들어갈때의 프래그먼트 전환을 F1의 매니저로 스택관리를 하는 방법이다.


번외 2.

이건 좀 이상한 현상인데, FragmentManager에서 getFragment()를 하면 List<Fragment>를 반환한다.

근데 replace를 하거나 스택을 쌓은 후 다시 back으로 스택을 없앴을 때 사이즈가 최대값으로 남아있는 현상이다.

예를 들어 F1을 F2로 replace한 후에 다시 F3, F4로 순서대로 스택을 쌓으면서 replace를 한다.

이후에 Back을 두번눌러서 F2로 돌아오면 매니저에 남아있는 fragment는 F2 하나여야 할 거 같은데(다 replace니까)

List<Fragment>.size()를 보면 4로 나온다. 매니저에 한번이라도 등록한건 죽을때까지 가지고 있는 것인가.

그런데 더 이상한 건, getFragments()로 얻어온 결과를 디버깅해서 보면 size는 4인데 분명히 실제값은 1개의 F2만 들어가있는

이해할 수 없는 상황이 벌어져있다는 것이다. 내가 뭘 잘못 알고 있는 건지, 안드로이드의 버그인지, 아니면 의도된 결과인지

전혀 모르겠다. 어쨋든 이점 때문에 히스토리관리를 fragment의 갯수로 하려는 방법은 무산된 상태이다.


반응형

댓글