[Android] Fragment
Fragment란??
Fragment란 하나의 Activity가 여러 개의 분할된 화면을 가지도록 만들기 위해 고안된 개념이다. 다양한 크기의 화면을 가진 모바일 환경이 늘어나고 태블릿의 큰 화면에 대한 Activity의 비효율성
이 부각되었다. 이처럼 하나의 디스플레이 화면 안에서 다양한 화면을 보여주고 싶은 니즈를 충족시키기 위해 등장한 것이 Fragment이다.
Fragment를 사용하면 다른 Activity에서도 재사용할 수 있다는 장점이 있다. 또한 전체 화면인 Activity에서 부분 화면을 만드는 데 주로 사용된다.
Fragment는 항상 Activity 위에 올라가 있어야 한다. 자체 생명주기를 갖지만, Activity의 생명주기에 종속적이다. Activity가 소멸되면 그 위의 Fragment도 소멸된다.
안드로이드 4대 컴포넌트(Activity, Service, Broadcast Receiver, Content Provider)들은 인텐트를 이용하여 상호 간에 통신을 진행한다. 하지만 Fragment는 안드로이드의 4대 컴포넌트에 속하는 구성 요소가 아니다. 따라서 인텐트를 사용하여 값을 전달할 수 없다.
그래서 Fragment 간에 값을 전달하고 상호 통신을 하기 위해서 고안된 것이 Bundle
이라는 것이다. Fragment는 Bundle이라는 객체를 통해서 Fragment 간의 데이터 전달을 수행한다.
추가 내용
Fragment는 자신이 속한 Activity와만 통신을 해야하며, 항상 자신이 속한 Activity를 통해서 다른 Fragment나 Activity와 통신해야 한다.
Fragment와 Activity가 통신할 수 있는 방법에는 3가지 방법이 있다.
- Bundle - Acticity는 Fragment를 생성 후, 데이터를 넣은 bundle을 전달할 수 있다. Fragment는 onActivityCreated() 메소드에서 bundle을 받게 된다.
- Method - Activity는 Fragment의 메소드를 호출할 수 있다.
- Listener - Fragment는 interface를 사용하여 Activity에서 리스너 이벤트를 발생시킬 수 있다.
하나의 Activity에 속하는 다수의 Fragment가 동시에 동작 가능하다. Activity는 한 화면을 다 차지해야 하는데 Fragment는 화면 일부만 점유해도 동작 가능하기 때문에 화면을 분할하여 부분마다 독립적인 유저 인터페이스를 구현할 수 있다. Activity의 일부분을 차지하는 각각의 Fragment는 자신만의 유저 인터페이스를 보여주고, 사용자의 입력에 반응한다.
기기의 화면 크기나 화면 방향 등에 따라 달라지는 Activity의 레이아웃에 맞추어 Fragment의 레이아웃을 재배열하거나 결합할 수 있다. 예를 들어 태블릿에서는 Activity에 두 개의 Fragment를 추가한 유저 인터페이스를 보여주지만 핸드폰에서는 Activity당 하나의 Fragment를 추가한 유저 인터페이스를 보여준다.
Fragment’s LifeCycle
Fragment는 생명 주기를 갖지만, Activity의 생명주기에 종속적인 특성이 있다.
-
onAttach()
- Fragment가 Activity에 추가될 때 한번 호출된다.
- 하지만 아직 완벽하게 생성된 것은 아니다.
- Fragment가 Activity에 대한 참조를 얻기 위해 사용되어진다.
-
onCreate()
- 본격적으로 Fragment가 Activity의 호출을 받아 생성되는 시점이다.
- Fragment의 생명주기는 Activity의 생명주기에 종속적이라고 앞에서 언급했다. 이 단계에서는 Activity도 생성 중에 있는 시기이기 때문에 Activity에 있는 컨트롤을 참조하거나 Fragment의 요소들을 초기화할 때 불안정한 경우가 있다.
- Activity의 onCreate()에서는 view, UI 작업을 할 수 있지만, Fragment의 onCreate()에서는 할 수 없다.
- Activity의 onCreate 메소드가 아직 완료된 시점이 아니라서 유저 인터페이스와 관련있는 것을 제외한 Fragment에서 사용되는 리소스들이 초기화된다.
- Fragment가 paused 또는 stop 되었다가 다시 resume되었을 때 유지하고 싶은 Fragment의 컴포넌트들을 여기서 초기화 해주어야 한다.
setRetainInstance(true)를 호출하여 Fragment의 인스턴스를 유지하도록 할 수 있다. 이 때 다음의 세가지가 기존과 달라진다.
- Activity가 재생성되어도 Fragment가 유지되기 때문에 onCreate는 호출되지 않는다.
- onDestroy()가 호출되지 않지만, Activity로부터 Fragment가 detach될 때 onDetach()는 호출된다.
- onAttach(Activity)와 onActivityCreated(Bundle)는 호출된다.
- onCreateView(LayoutInflater, ViewGroup, Bundle)
- Fragment에 속한 각종 View나 viewGroup에 대한 UI 바인딩 작업을 할 수 있다.
- Fragment의 유저 인터페이스가 화면에 그려지는 시점에 호출된다.
- XML 레이아웃을 inflate하여 Fragment를 위한 View를 생성하고 Fragment 레이아웃의 root에 해당되는 View를 Activity에게 리턴해야 한다.
inflate?
inflate는 XML 레이아웃에 정의된 뷰나 레이아웃을 읽어서 메모리상의 view 객체를 생성해주는 것이다.
-
onActivityCreated()
- Activity에서 Fragment를 모두 생성하고(View 생성) 난 다음에 호출된다.
- Activity에서 onCreate() 다음에 호출되는 메소드이다.
- Activity와 Fragment가 드디어 연결되는 시점이다.
- Activity와 Fragment의 View가 모두 생성된 시점이라 findViewById()를 사용하여 View 객체에 접근하는게 가능하다.
-
onStart()
- Fragment가 사용자에게 보여지기 전에 호출되는 함수이다.
- Fragment가 속한 Activity가 start 된 것과 관련있음.
-
onResume()
- Fragment가 비로소 화면에 보이는 단계이다.
- 사용자에게 focus를 잡은 상태.
- 사용자와의 상호 작용이 가능하다.
- Fragment가 속한 Activity가 resume된 것과 관련있음.
Fragment가 사용되지 않을 때 호출되는 함수들
-
onPause()
- Activity가 pause되어 Fragment는 사용자와의 상호작용을 중지한다.
- Fragment가 중지되는 시점을 정의한다. Fragment의 정지가 반드시 Fragment의 소멸을 의미하는 것은 아니지만 다시 해당 Fragment로 돌아온다는 보장도 없기 때문에 이 시점에서 남겨두어야 하거나 보존해야 할 자료들을 저장한다.
-
onStop()
- Activity에 의해 stop되었거나 Fragment의 수행이 Activity에 의해 수정되었을 경우로 Fragment는 더 이상 보이지 않게 되며, Fragment 기능은 중지한다.
Fragment가 destroy될 때 다음 순서대로 호출된다.
-
onDestroyView()
- Fragment가 화면에서 보이지 않고 View의 현재 상태가 저장된 후 호출된다.
- Fragment의 View들을 제거(destroy)한다.
- Back Stack을 사용했다면, 해당 Fragment로 돌아올 때 onCreateView()가 호출된다.
- onCreateView에서 초기화했던 UI들을 여기서 해제하면 된다.
-
onDestroy()
- Fragment를 더 이상 사용하지 않을 때 호출된다.
- Activity와 연결이 끊어진 상태는 아니지만 Fragment는 동작하지 않는다.
- Fragment를 제거하기 직전.
- 시스템에서 onDestory()가 항상 호출되는 것을 보장해주지 않는다.
-
onDetach()
- onDetach가 호출된 후, Fragment를 비로소 제거하고 Activity와의 연결도 해제한다.
- Framgnet의 View hierarchy가 더 이상 존재하지 않게 된다.
- 부모 Activity가 즉, 종속된 Activity가 생명주기를 완전하게 마치지 않고 종료되었다면 onDetach()는 호출되지 않을 수도 있다.
액티비티와 프래그먼트 차이
위에서 언급했듯이 태블릿이 등장하면서 큰 화면에 대한 액티비티의 비효율성이 부각되었다. 태블릿의 큰 화면에 여러 액티비티를 보여주기 위해 나온 것이 프래그먼트이다. 하나의 액티비티에 여러 레이아웃을 배치하여 구성할 수도 있지만 프래그먼트
를 사용하면 다른 액티비티에서도 재사용이 가능하고 자체 생명주기를 가지기에 생명주기에 따라 다양한 구현이 가능하다. 또한 자체 입력 이벤트를 가지기에 다이나믹한 인터렉션이 가능하다.
프래그먼트의 생명주기는 액티비티의 생명주기에 종속적이기에 액티비티에서 onCreate()
가 호출되면 프래그먼트에서는 onActivityCreated()
가 호출되고 액티비티에서 onPause()
가 호출되면 프래그먼트도 onPause()
가 된다.
프래그먼트에서 액티비티와 통신을 하려면 getActivity()를 호출하면 액티비티 객체를 사용할 수 있으며 프래그먼트에서 발생하는 이벤트는 onAttach()
에서 _interfactionListener_를 호출하고 액티비티에서 이것을 구현함으로써 이벤트에 대한 처리와 프래그먼트간 통신이 가능하다.
액티비티를 관리하는 스택이 있듯이 프래그먼트에도 백스택이라는 스택 구조가 존재하며 이것은 액티비티가 관리한다. FragmentTransaction
객체의 addToBackStack() 함수를 사용하여 프래그먼트를 백스택에 저장하면 사용자가 뒤로가기 버튼을 눌렀을 때 프래그먼트의 이전 상태로 되돌려주는 기능을 제공할 수 있다.