본문 바로가기

Programming/Android

Fragment - 2. 사용

사용자 인터페이스 추가


Fragment는 일반적으로 Activity의 사용자 인터페이스의 일부로 사용되며 자체 Layout으로 Activity에 기여한다.


Fragment에 대해 Layout을 제공하려면 반드시 onCreateView() 콜백 메서드를 구현하여야 한다. 이것은 Fragment가 자신의 Layout을 그릴 때가 되면 Android 시스템이 호출하는 것이다. 이 메서드의 구현은 반드시 View를 반환해야 한다. 이것은 Fragment Layout의 루트이다.

  ( - Fragment가 ListFragment의 서브 클래스인 경우,기본 구현이 onCreateView()로부터 ListView를 반환하므로 이를 구현하지 않아도 된다)

 

onCreateView()로부터 레이아웃을 반환하려면 이를 XML에서 정의된 레이아웃 리소스로부터 팽창시키면 됩니다. 이를 돕기 위해 onCreateView()LayoutInflater 객체를 제공합니다.

예를 들어 다음은 Fragment의 서브클래스로, example_fragment.xml 파일로부터 레이아웃을 로드합니다.

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);
   
}
}

onCreateView()로 전달된 container 매개변수가 상위 ViewGroup이며(액티비티의 레이아웃으로부터), 이 안에 프래그먼트 레이아웃이 삽입됩니다. savedInstanceState 매개변수는 Bundle이며, 프래그먼트가 재개되는 중에 프래그먼트의 이전 인스턴스에 대한 데이터를 제공합니다(상태 복원은 프래그먼트 수명 주기 처리에서 자세히 설명함).

inflate() 메서드는 다음과 같은 세 개의 인수를 취합니다.

  • 팽창시키고자 하는 레이아웃의 리소스 ID.
  • 팽창된 레이아웃의 상위가 될 ViewGroupcontainer를 전달해야 (실행 중인 상위 뷰에서 지정한 것과 같이) 시스템이 레이아웃 매개변수를 팽창된 레이아웃의 루트 뷰에 적용할 수 있으므로 중요한 과정입니다.
  • 팽창된 레이아웃이 팽창 중에 ViewGroup(두 번째 매개변수)에 첨부되어야 하는지를 나타내는 부울 값. (이 경우, 이것은 거짓입니다. 시스템이 이미 팽창된 레이아웃을 container— 안에 삽입하고 있기 때문입니다. true를 전달하면 최종 레이아웃에 중복된 뷰 그룹을 생성하게 됩니다).

이제 레이아웃을 제공하는 프래그먼트 생성하는 방법을 알게 되셨습니다. 다음은 프래그먼트를 액티비티에 추가해야 합니다.

액티비티에 프래그먼트 추가

프래그먼트는 보통 UI의 일부분으로 호스트 액티비티에 참가합니다. 이는 해당 액티비티의 전반적인 뷰 계층의 일부분으로 포함되게 됩니다. 프래그먼트를 액티비티 레이아웃에 추가하는 데에는 두 가지 방법이 있습니다.

  • 프래그먼트를 액티비티의 레이아웃 파일 안에서 선언합니다.

    이 경우, 프래그먼트에 대한 레이아웃 속성을 마치 뷰인 것처럼 나타낼 수 있습니다. 예를 들어, 다음은 프래그먼트가 두 개 있는 액티비티에 대한 레이아웃 파일입니다.

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       
    android:orientation="horizontal"
       
    android:layout_width="match_parent"
       
    android:layout_height="match_parent">
       
    <fragment android:name="com.example.news.ArticleListFragment"
               
    android:id="@+id/list"
               
    android:layout_weight="1"
               
    android:layout_width="0dp"
               
    android:layout_height="match_parent" />
       
    <fragment android:name="com.example.news.ArticleReaderFragment"
               
    android:id="@+id/viewer"
               
    android:layout_weight="2"
               
    android:layout_width="0dp"
               
    android:layout_height="match_parent" />
    </LinearLayout>

    <fragment> 안의 android:name 특성은 레이아웃 안에서 인스턴스화할 Fragment 클래스를 지정합니다.

    시스템은 이 액티비티 레이아웃을 생성할 때 레이아웃에서 지정된 각 프래그먼트를 인스턴스화하며 각각에 대해 onCreateView() 메서드를 호출하여 각 프래그먼트의 레이아웃을 검색합니다. 시스템은 프래그먼트가 반환한 View를 <fragment> 요소 자리에 곧바로 삽입합니다.

    참고: 각 프래그먼트에는 액티비티가 재시작되는 경우 프래그먼트를 복구하기 위해 시스템이 사용할 수 있는 고유한 식별자가 필요합니다(그리고, 개발자는 이것을 사용하여 프래그먼트를 캡처해 이를 제거하는 등 여러 가지 트랜잭션을 수행할 수 있습니다). 프래그먼트에 ID를 제공하는 데에는 다음과 같은 세 가지 방법이 있습니다.

    • 고유한 ID와 함께 android:id 특성을 제공합니다.
    • 고유한 문자열과 함께 android:tag 특성을 제공합니다.
    • 위의 두 가지 중 어느 것도 제공하지 않으면, 시스템은 컨테이너 뷰의 ID를 사용합니다.
  • 또는, 프로그래밍 방식으로 프래그먼트를 기존의 ViewGroup에 추가합니다.

    액티비티가 실행 중인 동안에는 언제든 액티비티 레이아웃에 프래그먼트를 추가할 수 있습니다. 그저 프래그먼트를 배치할 ViewGroup를 지정하기만 하면 됩니다.

    액티비티 내에서 프래그먼트 트랜잭션을 수행하려면(프래그먼트 추가, 제거 또는 교체 등), FragmentTransaction에서 가져온 API를 사용해야 합니다.FragmentTransaction의 인스턴스를 Activity에서 가져오는 방법은 다음과 같습니다.

    FragmentManager fragmentManager = getFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

    그런 다음 add() 메서드를 사용하여 프래그먼트를 추가하고, 추가할 프래그먼트와 이를 삽입할 뷰를 지정하면 됩니다. 예:

    ExampleFragment fragment = new ExampleFragment();
    fragmentTransaction
    .add(R.id.fragment_container, fragment);
    fragmentTransaction
    .commit();

    add()에 전달되는 첫 인수가 ViewGroup입니다. 여기에 프래그먼트가 리소스 ID가 지정한 바와 같이 배치되어야 하며, 두 번째 매개변수는 추가할 프래그먼트입니다.

    FragmentTransaction을 변경하고 나면, 반드시 commit()을 호출해야 변경 내용이 적용됩니다.

UI 없이 프래그먼트 추가

위의 예시에서는 UI를 제공하기 위해 프래그먼트를 액티비티에 추가하는 방법을 보여드렸습니다. 하지만 UI를 추가로 제시하지 않고 액티비티에 대한 백그라운드 동작을 제공하기 위해 프래그먼트를 사용할 수 있습니다.

UI 없이 프래그먼트를 추가하려면 액티비티로부터 가져온 프래그먼트를 add(Fragment, String)을 사용하여 추가합니다(이때, 프래그먼트에 대해 보기 ID가 아니라 고유한 문자열 "태그"를 제공합니다). 이렇게 하면 프래그먼트가 추가되지만, 이것은 액티비티 레이아웃 안에 있는 뷰와 연관되어 있지 않기 때문에 onCreateView()로의 호출은 받지 않습니다. 따라서 그 메서드는 구현하지 않아도 됩니다.

프래그먼트에 대해 문자열 태그를 제공하는 것은 엄밀히 말해 비 UI 프래그먼트에만 해당되는 것은 아닙니다. UI가 있는 프래그먼트에도 문자열 태그를 제공할 수 있습니다. 하지만 프래그먼트에 UI가 없는 경우라면 이를 식별할 방법은 문자열 태그뿐입니다. 액티비티에서 나중에 프래그먼트를 가져오고자 하는 경우, findFragmentByTag()를 사용해야 합니다.

예를 들어 어떤 액티비티에서 UI 없이 프래그먼트를 배경 작업자로 사용한다고 가정해봅시다. 이것의 예로 FragmentRetainInstance.java 샘플을 들 수 있으며 이는 SDK 샘플에 포함되어 있고(Android SDK Manager를 통해 이용 가능), 시스템에서<sdk_root>/APIDemos/app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java로 찾을 수 있습니다.