안드로이드 프래그먼트 기본 사용법. (Android Fragment)

2016. 4. 21. 17:24


1. 안드로이드 Fragment

안드로이드에서 화면에 출력되는 UI 구성의 가장 기본이 되는 요소는 Activity입니다. 안드로이드 앱이 TextView, Button 등의 위젯을 화면에 표시하기 위해서는 최소한 하나의 Activity는 가져야 하며, Activity가 화면에 표시되는 순간 자식 View 위젯들이 화면에 그려지게 됩니다. Activity는 일반적으로 화면을 가득 채우지만, 화면의 일부에만 표시되도록 만들어 다른 Activity위에 띄울 수도 있습니다.(다이얼로그 형태)


안드로이드 앱 개발자들은 이러한 Activity를 기준으로 한 화면에 표시될 UI를 구성할 수 있습니다. Activity내에 들어갈 구성요소들을, 여러 View 위젯들을 사용하여 구성해야 하죠.


안드로이드가 나온지 얼마 되지 않은 초기 시절에, 전화기와 같은 작은 화면을 가진 디바이스만 있을 때는 Activity단위로 UI를 구성하는데 큰 번거러움이 없었습니다. 화면 크기가 작아서 배치할 수 있는 구성요소가 많지 않고, 사용 방법이 다양하지 않았으니까요.


그런데 큰 화면을 가진 안드로이드 태블릿 디바이스가 나오면서 상황이 조금 달라졌습니다. 화면이 크다보니 많은 위젯들이 사용되어질 수 밖에 없는데, Activity 단위만으로는 그 복잡성을 커버하기가 쉽지 않아진 거죠. 물론 여러 종류의 Layout들로 영역을 구분짓는 방법을 사용해도 되지만 다이나믹한 동작(디바이스에 따른 View 보이기, 감추기, 위치이동 등)이 요구되는 UI를 작성하자니 여간 번거로운 작업이 아니었습니다.


이런 번거로움을 해결하기 위해 안드로이드 허니컴(3.0, API Level 11)부터 Fragment가 도입되었습니다. Fragment는 Activity 내에 생성되는, UI 구성을 여러 개의 모듈 단위로 작성할 수 있도록 해주는 기능입니다. 또한 한번 작성된 Fragment는 여러 Activity에서 재사용이 가능하므로 UI 구성에 소요되는 작업량을 많은 부분 감소시킬 수 있습니다.


이러한 Fragment를 구글에서는 다음과 같이 정의하고 있습니다.


프래그먼트는 자체 수명 주기를 가지고, 자체 입력 이벤트를 받으며, 액티비티 실행 중에 추가 및 제거가 가능한 액티비티의 모듈식 섹션이라고 생각하면 됩니다(다른 액티비티에 재사용할 수 있는 "하위 액티비티"와 같은 개념).

또한 Fragment에 대한 이해를 돕기 위해 작성된 예시 화면과 그에 대한 설명은 아래와 같습니다.


안드로이드 프래그먼트 예시


지금부터 Fragment를 사용하는 방법에 대해 알아보겠습니다.

2. Fragment 기본 사용법.

Fragment에 대한 기본 이해를 돕기 위해 간단한 형태의 예제를 작성하겠습니다.


예제 화면은 세 개의 Fragment와 하나의 Button으로 구성됩니다. 각 Fragment는 자신을 식별하기 위한 TextView를 가집니다. 예제를 실행하면 Fragment A는 화면 상단의 고정 위치에 출력되고, 그 밑에 Fragment B가 출력됩니다. 그 다음 Button을 클릭하면 Fragment B와 C가 매번 교체되도록 동작됩니다.


안드로이드 프래그먼트 예제 레이아웃


2.1 워크플로우

안드로이드 프래그먼트 예제 작성 절차


2.2 Activity에 Fragment 추가.

Activity에 Fragment를 추가하는 방법은 Layout 리소스 XML을 사용하는 것과 Java 코드에서 FragmentManager를 사용하여 ViewGroup에 지정하는 두 가지가 있습니다.


Layout 리소스 XML에 지정하는 방법은 처음 화면에 출력될 Fragment를 지정하거나 화면에서의 동적 변화(show/hide)가 없는 경우에 주로 사용합니다. 반면 FragmentManager를 사용하는 방법은 앱 실행 중 Fragment를 동적으로 추가하거나 변경할 때 사용합니다.


예제에서는 최초 출력될 Fragment를 아래와 같이 Activity에 추가하겠습니다. 아래의 내용 중 FrameLayout은 Fragment B와 C가 교체되어 표시될 ViewGroup으로 사용됩니다.

[STEP-1] "activity_main.xml" - MainActivity에 Fragment 추가. 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    android:orientation="vertical"
    tools:context="com.recipes4dev.examples.fragmentexample1.MainActivity"
    tools:showIn="@layout/activity_main">

    <fragment
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/fragmentA"
        android:name="com.recipes4dev.examples.fragmentexample1.FragmentA"
        android:layout_weight="1"
        tools:layout="@layout/activity_main" />

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:id="@+id/fragmentBorC" />

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Switch Fragment"
        android:textSize="20sp" />

</LinearLayout>

위의 코드에서 Fragment의 속성 중 "android:name"에는 화면에 출력할 Fragment 클래스를 지정합니다. Fragment는 개발자가 Layout을 만들어줘야 하기 때문에 Activity를 사용할 때와 마찬가지로 Fragment를 상속한 사용자 클래스를 만들어서 사용해야 합니다. 즉, "2.3 Fragment 클래스 상속 및 구현."에서 만들게 될 클래스를 "android:name"에 지정하는 것입니다.

2.3 Fragment를 위한 Layout 리소스 XML.

각 Fragment를 위한 Layout 리소스 XML을 작성합니다. 참고로 Fragment의 구분을 쉽게 하기 위해 Fragment의 LinearLayout에 "background" 속성을 사용하여 각각 다른 컬러를 지정하였습니다.

[STEP-2.1] "fragment_a.xml" - FragmentA의 Layout 리소스 XML

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFAAAA"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="30sp" android:text="Fragment A" android:gravity="center" /> </LinearLayout>

[STEP-2.2] "fragment_b.xml" - FragmentB의 Layout 리소스 XML

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#AAFFAA"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="30sp" android:text="Fragment B" android:gravity="center" /> </LinearLayout>

[STEP-2.3] "fragment_c.xml" - FragmentC의 Layout 리소스 XML

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#AAAAFF"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="30sp" android:text="Fragment C" android:gravity="center" /> </LinearLayout>

2.4 Fragment 클래스 상속 및 구현.

Fragment를 상속받은 FragmentA, FragmentB, FragmentC 클래스를 생성합니다.

[STEP-3.1] "fragmentA.java" - FragmentA 클래스
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class FragmentA extends Fragment { public FragmentA() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_a, container, false); } }
[STEP-3.2] "fragmentB.java" - FragmentB 클래스
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class FragmentB extends Fragment { public FragmentB() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_b, container, false); } }
[STEP-3.3] "fragmentC.java" - FragmentC 클래스
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class FragmentC extends Fragment { public FragmentC() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_c, container, false); } }


2.5 Activity의 onCreate()에서 Fragment 초기화

각 Fragment에 대한 Layout 리소스 XML를 작성하고 클래스도 구현하였으니, Java 코드에서 Fragment를 추가하는 코드에 대해 설명하겠습니다.


Java 코드에서 Fragment를 다룰 때는 FragmentManager와 FragmentTransaction 클래스를 사용합니다.


사용 방법은 매우 간단합니다. Activity 클래스의 getFragmentManager() 함수를 사용하여 FragmentManager에 대한 참조를 획득한 다음, FragmentManager의 beginTransaction() 함수를 호출하여 FragmentTransaction을 시작합니다.
그런 다음 FragmentTransaction의 add() 함수를 이용하여 Fragment를 Activity의 ViewGroup(FrameLayout)에 추가합니다. Fragment와 관련된 모든 작업이 완료되면 FragmentTransaction의 commit() 함수를 호출하여 Fragment와 관련된 작업이 완료되었음을 알려줍니다.


예제에서 작성한 Activity의 onCreate() 함수는 아래와 같습니다.

[STEP-4] "MainActivity.java" - onCreate() 함수에서 Fragment 추가.
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ... 코드 계속

        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fm.beginTransaction();
        fragmentTransaction.add(R.id.fragmentBorC, new FragmentB());
        fragmentTransaction.commit();

        // 코드 계속 ...
    }

Fragment의 Transaction과 관련하여 중요한 내용 중에 addToBackStack() 함수가 있습니다. 바로 commit()이 실행되기 이전 상태를 "백 스택"에 추가할 수 있는 함수입니다. "백 스택"에 들어간 내용은 Activity에 의해 관리되며, "뒤로(Back)" 버튼을 누르면 이전 상태에 저장된 Fragment를 다시 가져올 수 있는 것이죠.
addToBackStack() 함수의 사용에 대한 내용은 다음 기회에 자세히 다루겠습니다.

2.6 Button 클릭 시, FragmentTransaction을 사용한 Fragment 교체

마지막으로 Button이 클릭되면 Fragment가 교체되는 기능을 작성합니다. onCreate() 함수 내용과 마찬가지로 Fragment를 제어하는 기능이 구현되므로 FragmentManager와 FragmentTransaction을 사용합니다.

[STEP-5] "MainActivity.java" - Button 클릭 시 Fragment 교체.
public class MainActivity extends AppCompatActivity {

    private boolean isFragmentB = true ;

    // ... 코드 계속
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ... 코드 계속 [STE]

        Button button1 = (Button) findViewById(R.id.button1) ;
        button1.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
                switchFragment() ;
            }
        });
    }

    public void switchFragment() {
        Fragment fr;

        if (isFragmentB) {
            fr = new FragmentB() ;
        } else {
            fr = new FragmentC() ;
        }

        isFragmentB = (isFragmentB) ? false : true ;

        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fm.beginTransaction();
        fragmentTransaction.replace(R.id.fragmentBorC, fr);
        fragmentTransaction.commit();
    }
}

3. Fragment 예제 실행 화면

아래는 예제 실행 화면입니다.


안드로이드 프래그먼트 예제 실행 화면


예제는 다음과 같이 동작합니다.

4. 참고.

.END.


ANDROID 프로그래밍/FRAGMENT