목 차
1. 등장배경
2. Fragment 클래스
Java Code
XML Layout (example_fragment.xml)
3. 라이프사이클
Activity Created
Activity Started
Activity Resumed
Activity Paused
Activity Stopped
Activity Destroyed
4. Activity에 붙이는 방법
A. Static 방법
B. Dynamic 방법
5. 참고
6. 시리즈 연재
1. 등장배경
우선 언제 Fragment를 사용하는지부터 살펴보자.
Activty A와 Activity B는 서로 다른 UI를 가지지만 일부 같은 UI를(빨간색) 가진다. 이런 경우 같은 UI 부분을 공통 모듈로 빼고 싶다 ⇒ 공통 UI 부분을 Fragment
Activity X와 Y는 일반적인 스마트폰 UI를 구성하고 있다.
Activity Q는 Landscape(가로) 화면일 때, 보여주고 싶은 화면이다.
가끔 태블릿 같은 대화면 디바이스가 나타나면 Portrait(세로) 화면이라도 Activity P와 같은 화면을 보여주고 싶다.
Activity X / Activity Y의 UI를 Fragment화한다. Q와 P에서는 Fragment를 이용하는 형태로 구현한다.
구현이야 하면 된다. 다만 ‘잘’ 구현하는 것은 쉽지 않다. 위의 예들을 보면 UI 컴포넌트를 ‘모듈화’시켜서 ‘재사용’하면 좋을 것 같다는 생각이 (당연히) 들거다. 정리하자면 Fragment는 Activity의 전체 UI 중에 일부분을 담당해주는 UI 조각이다. 참고로 Fragment의 사전적 의미 또한 ‘조각’, ‘파편’ 이다.
Fragment의 등장은 태블릿의 등장과 관련되어 있다. Activity 포스팅에서 Activity는 기본적으로 한 가지 작업을 위해 만들어진 컴포넌트라고 했다. 일반적인 경우에는 이런 Activity에 대한 전제가 문제 없이 잘 동작했다. 하지만 화면이 큰 디바이스들이 등장하면서 이런 전제가 흔들리기 시작했다. 큰 화면의 디바이스의 경우, 기존 방식으로 개발된 앱들이 화면 공간을 낭비하는 문제가 발생하게 된 것이다.
때문에 디바이스의 화면 크기에 따라서 2개 이상의 Activity를 표현할 수 있는 방법이 필요했다. 하지만 Activity는 이미 시스템의 주요 구성요소였고 Activity의 동작 방법을 바꿀 경우, 다른 플랫폼 요소에 미치는 영향이 커질 수 밖에 없었을 것이다. 때문에 등장한 것이 Fragment이다.
관련된 유투브 동영상도 한번 보자. 참고로 한글 자막이 지원된다.
이제 자연스럽게 떠오르는 고민은 이거 일거다. ‘굳이 Fragment를 써야 하는가?’
여기저기 관련 내용을 살펴보면서 든 생각은 아래와 같은 상황이면 쓸 필요가 없을 것 같다. 아~! 물론 개인적인 의견이다. (방어로직 발동)
태블릿 / 스마트폰이 동일 UI로 갈 경우
UI 자체가 굉장히 심플 할 경우
언젠가는 Fragment를 도입하려는 앱의 경우는 머리가 복잡해진다. 점진적 개발방법과 ‘Time to market’의 중요성을 봤을 때, 초기 버전의 앱이 복잡할 가능성은 낮아 보인다. 따라서 Fragment를 쓰지 않고 앱을 구현하는 것이 이득일 수 있다. 슬픈 이야기지만 초기 버전 이후에 앱 개발이 중단될 가능성도 또한 높다. 다만 원대한 목표(?)를 가지고 앱을 개발한다면 초기부터 Fragment를 도입해서 구현하는 것도 나쁘지 않겠다.
물론 Fragment에 익숙하다면 당연히 Fragment를 사용해서 구현하는 것이 올바른 방향일 것 같다.
마지막으로 안드로이드 펍에 올라온 글을 소개해본다. ‘실무에서 바로 적용하는 안드로이드 프로그래밍’ 이라는 책에서 발췌 했다고 하는데 요약하자면 다음과 같은 말이다.
Fragment로 구현된 모든 것은 Activity 만으로도 구현할 수 있다.
간단한 UI의 경우 Fragment를 사용할 경우 코드 양이 더 많아 진다.
YAGNI (You aren’t gonna need it) 원칙 : 나중에 필요하다고 생각하는 코드를 지금 작성하지 않는다.
Fragment의 경우, AUF (Always use fragment) 원칙을 사용한다. 왜냐하면 기존 형태 ⇒ Fragment 형태는 굉장한 고통과 골칫거리를 수반하기 때문이라고…
정리하자면 무조건 Fragment를 사용하라는 뜻이다. 약간의 코드 추가를 통해서 장기적인 유지보수의 장점을 얻는다니 최대한 사용하도록 노력해보자.
2. Fragment 클래스
Fragment의 실체는 Activity와 크게 다를 것이 없다. [Java 클래스 + XML Layout]이 그 실체다. 만약 Static하게 Activity에 붙인다면 (이후에 설명된다) XML Layout만 있어도 된다. 하지만 코드레벨의 분리를 위해서는 [Java 클래스 + XML Layout]를 선택하자.
Java Code
public static class ExampleFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.example_fragment, container, false); } } |
XML Layout (example_fragment.xml)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TEST" />
</LinearLayout> |
Fragment는 공식적으로는 허니콤 버전부터 사용할 수 있다. ‘공식적’이라는 표현을 사용한 이유는 구글에서 배포한 라이브러리를 사용할 경우, 허니콤 이전 버전에서도 구현할 수 있기 때문이다.
앞에서 말했듯이 Fragment는 Activity 내에서 일부 UI를 담당하는 역할을 한다. 따라서 Activtiy와 마찬가지로 하나의 XML layout과 같이 움직인다고 보면 된다. 여러 Fragment는 하나의 Activity 내에서 존재할 수 있고 하나의 Fragment는 여러 Activity 들에서 재사용 될 수도 있다.
3. 라이프사이클
Activity가 Fragment를 감싸고 있는 구조이다. 따라서 기본적인 Lifecycle은 Activity의 Lifecycle과 관계가 있을 수 밖에 없다. 우선 아래 그림을 보자.
Activity Created
onAttach()
Fragment가 Activity에 최초로 연결될 때 호출된다. Fragment를 붙이는 방법에 따라서 호출되는 시점이 다른데 Static하게 붙였다면 Activity가 시작될 때 같이 호출이 되고 Dynamic하게 붙였다면 FragmentManager에 의해서 Activity에 연결될 때 호출된다.
onCreate()
Fragment를 초기화하는 메소드이다. 최초로 생성될 때 호출된다.
onCreateView()
여기서 레이아웃 inflater 작업이 진행된다. 아래는 예.
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.example_fragment, container, false); } |
onActivityCreated()
Activity의 onCreate에서 UI 작업이 마무리 된 이후 시점이라고 생각하면 된다. Fragment가 Activity에 완벽하게 연결이 된 상태이다.
Activity Started
onStart()
부모 Activity가 화면에 보이게 되면 호출된다.
Activity Resumed
onResume()
부모 Activity가 유저 Input을 받을 준비가 되면 호출된다.
Activity Paused
onPause()
부모 Activity가 화면에는 보이지만 포커스를 잃게 되면 호출된다.
Activity Stopped
onStop()
부모 Activity가 더이상 화면에 보이지 않게 되면 호출된다.
Activity Destroyed
onDestroyView()
onCreateView()에서 호출된 View들이 Activity에서 제거되면서 호출된다. 일반적으로 View 리소스를 해제하는데 사용된다.
onDestroy()
onCreate()에 대응되는 함수로 Fragment가 더이상 유효하지 않을 때 호출된다. 일반적으로 Fragment 자체 리소스를 해제하는 용도로 사용된다.
onDetach()
Fragment가 더이상 Activity에 연결되어 있지 않은 상황에서 호출된다. 일반적으로 부모 Activity에서 Fragment의 참조를 가지고 있다면 null로 바꿔주는 작업을 수행한다.
4. Activity에 붙이는 방법
두 가지 방법이 있다.
Static 방법 : 레이아웃 파일에 선언해서 붙이기
Dynamic 방법 : fragmentManager를 통해서 붙이기
A. Static 방법
Activity가 사용하는 layout에 Fragment를 그대로 붙이는 방법이다. 기존의 View를 붙이는 것과 다를 게 없다.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <fragment android:id="@+id/fragment" android:name="example.fragment" android:layout_width="fill_parent" android:layout_height="fill_parent"/> </LinearLayout> |
B. Dynamic 방법
Activity가 이미 화면에 보이는 상황에서 Runtime으로 Fragment를 붙이는 방법이다. 기본적으로 아래의 코드 구조를 가진다.
FragmentManager fragmentManager = getFragmentManager(); TestFragment frament = new TestFragment(); Bundle bundle = new Bundle(); frament.setArguments(bundle); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.add(R.id.container, fragment); fragmentTransaction.commit(); |
FragmentManager를 얻는다.
FragmentTransaction을 시작한다.
Fragment를 붙인다.
FragmentTransaction을 커밋 한다.
FragmentTransaction를 통해 Fragment를 붙일 때에는 아래 선택사항이 있다.
add 메소드 이용 : 기존에 Fragment가 존재한다면 계속 쌓임 ⇒ 리소스 낭비/성능저하
replace 메소드 이용 : 기존의 Fragment를 제거하고 붙음
아래는 유투브에 올라온 Fragment 실습 동영상이다. 관심 있으면 살펴보자.
5. 참고
6. 시리즈 연재
'소프트웨어 > 안드로이드앱' 카테고리의 다른 글
[안드로이드 기초#7-2] UI 클래스들 (0) | 2015.07.06 |
---|---|
[안드로이드 기초#7-1] UI 클래스들 (0) | 2015.07.05 |
[안드로이드 기초#5] 권한 (Permission) (0) | 2015.07.03 |
[안드로이드 기초#4] 인텐트 (Intent) (0) | 2015.07.02 |
[안드로이드 기초#3] 액티비티 (Activity) (0) | 2015.07.01 |