태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.

프래그먼트(Fragment) 정복! - (2) 프래그먼트 자세히 알아보기

2011.05.19 13:02

프래그먼트를 가장 간단하게 표현하자면 '뷰(View)처럼 사용할 수 있는 액티비티(Activity)'라 할 수 있습니다. 즉, 액티비티와 뷰의 특징을 모두 가지고 있습니다. 프래그먼트는 뷰에게 레이아웃 내에 자유롭게 배치될 수 있는 특징을 물려받았는데, 그렇다면 액티비티에서는 어떤 특징을 물려받았을까요? 바로 '생애주기'를 갖는 특징입니다.

프래그먼트의 생애주기


 프래그먼트는 액티비티와 같이 프래그먼트의 상태가 계속해서 변하며, 상태가 변할 때마다 그에 해당하는 생애주기 메서드(콜백 메서드)가 호출됩니다. 프래그먼트의 생애주기 메서드 및 각 메서드의 호출 순서는 다음과 같습니다.

프래그먼트의 생애주기 메서드


각 생애주기 메서드에 대해 더 자세히 알아보도록 하겠습니다. 액티비티의 생애주기 메서드와 매우 유사한 형태를 띄고 있으며, 뷰 생성과 관련된 몇몇 메서드가 더 추가되어 있습니다.

onAttach(Activity)
프래그먼트가 액티비티 레이아웃에 포함되는 순간 호출됩니다. 액티비티 레이아웃에 프래그먼트를 정적으로 배치했다면 액티비티가 시작될 때 같이 호출되며, 동적으로 레이아웃에 추가할 땐 프래그먼트를 레이아웃에 추가하는 순간 호출됩니다.


onCreate(Bundle)
액티비티의 onCreate() 콜백 메서드와 유사하게 프래그먼트가 최초로 생성될 때 호출됩니다.


onCreateView(LayoutInflater, ViewGroup, Bundle)
프래그먼트의 UI를 구성하는 뷰(View)를 반환합니다. UI를 가지지 않는 프래그먼트일 경우 null을 반환할 수도 있습니다.


onStart()
프래그먼트가 화면에 표시될 때 호출됩니다. 하지만, 아직 사용자와 상호작용은 할 수 없는 상태입니다.


onResume()
프래그먼트가 사용자와 상호작용을 할 수 있게 되었을 때 호출됩니다. 즉, 프래그먼트가 완전히 화면에 표시되어 제 역할을 수행할 수 있게 된 상태입니다.


onPause()
액티비티의 onPause()와 유사하게 프래그먼트가 사용자와 상호작용을 할 수 없게 될 때 호출됩니다. 프래그먼트가 아직 화면에 표시되고 있는 상태이나, 다른 요소에 의해 프래그먼트가 가려져 상호작용을 하지 못하는 상태입니다.


onStop()
프래그먼트가 화면에서 보이지 않게 될 때 호출됩니다. 액티비티가 화면에서 보이지 않게 될 때 onStop() 메서드가 호출되는 것과 유사합니다.


onDestroyView()
프래그먼트가 화면에서 사라진 후, 뷰의 현재 상태가 저장된 후 호출됩니다. 여기에서 저장된 뷰의 상태는 액티비티와 유사하게 Bundle 형태로 저장되며, 저장된 뷰의 상태는 onCreate() 및 onCreateView()에서 다시 불러들일 수 있습니다.


onDestroy()
프래그먼트가 더 이상 사용되지 않을 때 호출됩니다. 


onDetach()
프래그먼트가 액티비티 레이아웃에서 제거될 때 호출됩니다. 


위와 같이 프래그먼트의 생애주기는 액티비티와 매우 유사합니다. 때문에 기존에 액티비티로 작성되어 있던 코드를 쉽게 프래그먼트로 옮겨올 수 있습니다. 

프래그먼트에는 위의 생애주기 메서드 외에도 프래그먼트를 포함하고 있는 액티비티의 생성이 완료되었을 때 호출되는 콜백 메서드도 포함하고 있으며, 그 메서드는 다음과 같습니다.

onActivityCreated(Bundle)
프래그먼트를 포함하고 있는 액티비티의 생성이 완료되었을 때, 즉 액티비티의 onCreate() 메서드가 끝났을 때 호출됩니다.


프래그먼트를 레이아웃에 추가하기 (XML 사용)


프래그먼트의 특징에 대해 간단히 알아보았으니, 우선 프래그먼트를 레이아웃에 추가하는 방법에 대해 알아보도록 하겠습니다. 프래그먼트를 레이아웃에 추가하는 방법은 여러 가지가 있지만, 그 중에서도 가장 간단한 방법인 XML 레이아웃을 사용하여 추가하는 방법을 알아보겠습니다.

[어플리케이션 정보]

액티비티
  • Main (Main.java)

레이아웃
  • main.xml (Main)
  • fragment_one.xml (FragmentOne 프래그먼트)

API Level
  • Android 3.0 (API Level 11)



우선, 프래그먼트에 표시할 레이아웃 파일을 작성합니다. 다음과 같이 fragment_one.xml 레이아웃 파일을 추가한 후,TextView 하나를 추가합니다.

[fragment_one.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="Fragment One" />
  
</LinearLayout>

액티비티 코드에 프래그먼트 클래스를 추가한 후, 프래그먼트에 표시할 뷰를 지정해주기 위해 onCreateView() 다음과 같이 메서드를 오버라이드합니다. 프래그먼트에서 표시할 뷰를 반환하기 위해 onCreateVIew()의 인자 중 하나인 LayoutInflater를 사용합니다.


[Main.java]
public class Main extends Activity {
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    
    public static class FragmentOne extends Fragment{

		@Override
		public View onCreateView(LayoutInflater inflater, ViewGroup container,
				Bundle savedInstanceState) {
			return inflater.inflate(R.layout.fragment_one, null);
		}
    	
    }
    
}

다음, 액티비티의 레이아웃을 작성합니다. 프래그먼트를 XML 레이아웃 파일에서 선언할 때는 프래그먼트의 클래스(class)와 프래그먼트를 구분할 수 있는 id 혹은 tag를 필히 지정해야 합니다. 여기에서는 프래그먼트를 구분하기 위해 id를 지정해 주었습니다.

이 예제에서 프래그먼트 클래스가 Main 클래스의 내부 클래스로 선언되어 있기 때문에 Main$FragmentOne과 같이 클래스 이름을 지정해 주었습니다.


[main.xml]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
>
	<fragment
		android:id="@+id/fragment_one"
		class="com.androidhuman.example.SimpleFragment.Main$FragmentOne"
		android:layout_width="match_parent"
		android:layout_height="match_parent" />
</LinearLayout>


이것으로 모든 구현이 끝났습니다. 생각보다 간단하지요? 예제를 실행하면 다음과 같이 프래그먼트가 표시되는 것을 확인할 수 있습니다.


프래그먼트라는 것을 처음 접할 때는 아직 익숙하지 않아 어려워 보였을지도 모릅니다. 간단한 예제를 통해 알아본 것과 같이 접해보면 그리 어렵지 않습니다.

다음 포스트에서는 프래그먼트를 사용하는 가장 큰 장점 중 하나라 할 수 있는 프래그먼트 전환에 대해 다루어보도록 하겠습니다. :)




저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

커니 유저 인터페이스/프래그먼트(Fragment) , , , , , , , ,

  1. Blog Icon
    우와.

    감사합니다.^^

  2. onCreateView() 다음에 onViewCreate()가 빠져있는 건가요??
    커니님 책에는 onViewCreate()가 들어가있는데;;

    그리고 http://developer.android.com/guide/topics/fundamentals/fragments.html
    여기 보시면 onViewCreate()자리에 onActivityCreate()가 들어가있습니다.

    어느게 맞는건지;;
    별 상관은 없는건가요??

  3. onCreateView() 다음에 onViewCreate()가 빠져있는 건가요??
    커니님 책에는 onViewCreate()가 들어가있는데;;

    그리고 http://developer.android.com/guide/topics/fundamentals/fragments.html
    여기 보시면 onViewCreate()자리에 onActivityCreate()가 들어가있습니다.

    어느게 맞는건지;;
    별 상관은 없는건가요??

  4. 초창기 프래그먼트가 소개되었을 때 onActivityCreated()가 호출되었을 때 프래그먼트의 뷰가 만들어진 상태라, 뷰 내의 객체에 접근하는 것이 가능했습니다.

    그래서, 이러한 모호함을 없애기 위해 3.1버전부터는 onViewCreated()라는 콜백 메서드가 생겼습니다.

    onActivityCreated()와 onViewCreated()는 대부분 거의 동시에 호출된다 보셔도 무방합니다 :)

  5. Blog Icon
    batman

    일반 단말에서는 안되는 건가요? 태블릿이 아니라서 그런지 단말 두개다 에러가 나네요.

  6. 3.0 이상 단말기면 모두 동작합니다.
    어떤 에러가 나는건가요?

  7. Blog Icon
    batman

    제가 착각하고 있었나봅니다. 낮은버젼에서 fragment를 android_support_v4를 참조하여 사용할 수 있는지 알았습니다.
    태블릿에서 잘 되네요.

    답변주셔서 감사드립니다.

  8. 낮은 버전에서 사용할 경우 import부분의 android.app.Fragment를 android.app.support.v4.Fragment (맞나요?!)로 바꿔줘야 합니다.
    Support library에 있는 Fragment를 참조하도록 바꿔야합니다~

  9. 커니님 글에 많은 도움을 받고 있습니다.
    저도 프레그먼트를 써보려구 합니다.
    감사합니다.

  10. Blog Icon
    오늘도감사

    프래그먼트에 대해 자세히 설명해 주셔서 너무 감사요.
    그런데, 두가지 질문이 있습니다.

    1. 안드로이드 이전 버전의 책 밖에 구할 수 없어서 그책으로 공부 중인데, OnCreateView에 OnTouch 액션을 구현하면 동작하지 않습니다.
    2. OnCreate 함수 안에는 뭘 구현해도 실행 시 에러가 나던데, 거긴 사용자가 사용할 수 없는 영역인가요?

  11. onCreateView에 onTouch액션을 구현한다는 것은 인스턴스를 생성한 것을 말씀하신 건가요? 제대로 구현이 되었다면 동작하는 것이 맞는데, 말씀주신 내용만으로는 뭐가 문제인지 알 수가 없네요.

    마찬가지로 onCreate()에서 에러가 난다고 하셨는데, 어떤 에러가 나는지 로그를 확인하지 않는 이상 자세한 내용을 알려드릴 수 없습니다. 로그를 알려주세요.

  12. Blog Icon
    쏭아리

    안녕하세요. 항상 블로그로 도움 많이 받고 있습니다.
    그런데 오늘은 이 간단한게 왜 안될까요. 앱이 화면이 안나오고 죽습니다.
    아래는 죽으면서 나오는 로그이고요.

    08-21 16:13:19.241: E/AndroidRuntime(16668): FATAL EXCEPTION: main
    08-21 16:13:19.241: E/AndroidRuntime(16668): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.simplefragment/com.example.simplefragment.MainActivity}: android.view.InflateException: Binary XML file line #8: Error inflating class fragment
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2308)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2362)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.app.ActivityThread.access$700(ActivityThread.java:168)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1329)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.os.Handler.dispatchMessage(Handler.java:99)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.os.Looper.loop(Looper.java:176)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.app.ActivityThread.main(ActivityThread.java:5493)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at java.lang.reflect.Method.invokeNative(Native Method)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at java.lang.reflect.Method.invoke(Method.java:525)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1225)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1041)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at dalvik.system.NativeStart.main(Native Method)
    08-21 16:13:19.241: E/AndroidRuntime(16668): Caused by: android.view.InflateException: Binary XML file line #8: Error inflating class fragment
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:762)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.view.LayoutInflater.rInflate(LayoutInflater.java:804)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.view.LayoutInflater.inflate(LayoutInflater.java:526)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.view.LayoutInflater.inflate(LayoutInflater.java:426)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.view.LayoutInflater.inflate(LayoutInflater.java:382)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:361)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.app.Activity.setContentView(Activity.java:1956)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at com.example.simplefragment.MainActivity.onCreate(MainActivity.java:17)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.app.Activity.performCreate(Activity.java:5372)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1104)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2270)
    08-21 16:13:19.241: E/AndroidRuntime(16668): ... 11 more
    08-21 16:13:19.241: E/AndroidRuntime(16668): Caused by: android.app.Fragment$InstantiationException: Trying to instantiate a class com.example.simplefragment.MainActivity$FragmentOne that is not a Fragment
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.app.Fragment.instantiate(Fragment.java:584)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.app.Fragment.instantiate(Fragment.java:560)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.app.Activity.onCreateView(Activity.java:4958)
    08-21 16:13:19.241: E/AndroidRuntime(16668): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:738)
    08-21 16:13:19.241: E/AndroidRuntime(16668): ... 21 more
    08-21 16:13:19.241: E/AndroidRuntime(16668): Caused by: java.lang.ClassCastException
    08-21 16:13:19.241: E/AndroidRuntime(16668): ... 25 more

    제 소스도 보여드려야겠죠? (제 눈엔 잘못된게 안보여요 ㅡㅡ;; )

    package com.example.simplefragment;

    import android.app.Activity;
    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;

    public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    }

    public static class FragmentOne extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_one, null);
    }
    }

    }

    이것과 xml 두개요
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <fragment
    android:id="@+id/fragment_one"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    class="com.example.simplefragment.MainActivity$FragmentOne" />

    </LinearLayout>

    두번째 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"
    android:orientation="vertical" >

    <TextView
    android:id="@+id/textView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Fragment One" />

    </LinearLayout>

    뭐가 문제인가요?

  13. Blog Icon
    쏭아리

    ㅎ 안녕하세요. 지난번에 질문했던거 해결했습니다. (그래도 자답 올립니다^^;)
    제가 import를 import android.support.v4.app.Fragment;
    이거를 해놔서. 이럴때에는 FragmentActivity로 해야만 되더라고요.
    진저 버전을 support 안하면 Activity, support하려면 FragmentActivity로 해야한다는 걸 또 배웁니다.

  14. 자답 올려주셔서 감사합니다! :)

  15. Blog Icon
    유길상

    안녕하세요 ! 글 잘보고 있는데 워낙 초보라서요..

    제가 메인기능 두개를 합치려고하는데 하나는 메인액티비티가 public class ___extends Activity 이렇게 시작하고 다른하나는 public class ___extends FragmentActivity 이렇게 시작해서 어떻게 합쳐야할지 모르겠습니다.

    버튼을 눌러서 다른 액티비티로 가는건 성공했는데 한 화면에 두가지 기능을 넣으려니 문제가 되는것 같습니다..

    메인화면에 여러가지 버튼이 있는상태에서 가운데에 구글맵 (여러기능포함) 을 띄우려고 하거든요..각각 따로 어플을 만들땐 메인액티비티라 간단했는데 막상 합치려니 어떻게 해야할지 감이 안옵니다 ㅜㅜ 같은 Activity라면 함수부분을 적절히 복사붙여넣기 해서 될텐데...하나는 activity고 하나는 FragmentActivity라서 맘대로 합칠수가 없더라구요 ㅜㅜ 조언좀 해주실수 잇나요?>?

  16. 액티비티 내부에 넣으려 하는 부분이 꼭 액티비티의 기능이 필요한 부분인가요? 그렇다면 액티비티 대신 프래그먼트를 사용해여 하당 부분을 감싸고, 감싼 부분을 액티비티에 넣는 방식을 사용하면 됩니다.

  17. Blog Icon
    limsuheyon

    public class SourceActivity extends Fragment{
    private TabHost mTabHost;
    private ListView lvKeyword;
    private KeywordAdapter adapterKeyword;
    private ArrayList<Keyword> listKeyword;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
    super.onCreateView(inflater, container, savedInstanceState);

    View v = inflater.inflate(R.layout.activity_source, container, false);


    setupTabHost(v);

    setupTab(new TextView(getActivity()), "행사시간표";);
    setupTab(new TextView(getActivity()), "espots대회시간표";);

    reLoad(v);

    //init(v);

    return v;
    }
    여기서 Activity는 사용할 수 없나요? Fragment탭에 지도를 넣으려니 ~extend Fragment에 오류가 걸리네요.

  18. Blog Icon
    Ngos1203

    안녕하세요~ 항상 커니님 블로그 보면서 안드로이드 공부하는데 도움이 많이 된답니다~ 감사드려요!
    프래그먼트를 공부하던 도중 프래그먼트를 중첩하여 사용하고싶은데 감이 안잡혀서 이렇게 질문 드립니다~

    예를 들면 같은 Activity 안에 A프래그먼트와 B프래그먼트가 존재하는데 A프래그먼트 위에 B프래그먼트를 올리고싶어요!

    B프래그먼트는 배경이 투명해서 A layout 위에 A프래그먼트가 존재하고 B layout 위에 B프래그먼트가 있는데
    (A layout과 B layout은 frame layout 안에 있어서 서로 중첩되어 보인답니당!)
    B프래그먼트를 add 하니 A 프래그먼트가 사라지더라구요ㅠㅠㅠ

    조언을 좀 얻고자 이렇게 질문 올립니다~
    조금 시간이 지난 글이라서 보실진 모르겠지만 ㅎㅎㅎ... 항상 블로그 잘 보고있습니다 감사해요!

  19. Blog Icon
    안드로이드를 정복하는 그날까지

    안녕하세요. 커니님~
    안드로이드 공부를 하게 된 한 학생입니다.

    다른 책으로 안드로이드를 공부중인데 제가 이해를 잘 못해서 많이 어려운데 커니님 블로그에 와서 한번 읽고 다시 책을 보면 이해가 정말로 잘됩니다!
    많은 도움을 주셔서 감사합니다.

    안드로이드를 정복하는 그날까지 달려가겠습니다.

  20. Blog Icon
    김진우

    fragment 생명주기 설명이 깔끔하네요 감사합니다~~!!
    개인적으로 git 정리를 하고 있는데
    조금만 참고할게요^^(출처는 꼭 기입하겠습니다)