11 프래그먼트란?
11-1 프래그먼트에 대해 이해하기
여러 개의 화면을 구성할 때는 보통 각각의 화면을 액티비티로 만든 후 액티비티를 전환하는 방법을 사용한다. 그런데 화면의 일부분을 다른 화면으로 구성하고 싶을 때는 어떻게 해야 할까?
① 리니어 레이아웃 안에 다른 레이아웃을 추가하고 각각의 레이아웃 안에 필요한 뷰를 넣는다.
② 프레임 레이아웃 안에 여러 개의 레이아웃을 넣어 중첩시킨 후 가시성 속성을 설정한다.
③ 하나의 액티비티 안에 여러 개의 액티비티를 부분 화면으로 설정한다.
위 세 가지 방법은 이전 게시글에서 배웠다. 방법 ①은 코드가 복잡해지는 문제가 있고, 방법 ②는 다른 액티비티에서 사용하려 할 때 동일한 레이아웃을 중복해서 만들어야 하는 문제가 있다. 방법 ③은 시스템에서 액티비티를 구성 요소로 관리하는 안드로이드에겐 단말의 리소스를 많이 사용하는 비효율적인 방법이다.
이때 사용할 수 있는 것이 프래그먼트(Fragment)이다. 프래그먼트는 하나의 화면을 여러 부분으로 나눠서 보여주거나 각각의 부분 화면 단위로 바꿔서 보여주고 싶을 때 사용할 수 있다.
프래그먼트 사용 목적 |
분할된 화면들을 독립적으로 구성하기 위해 사용함 |
분할된 화면들의 상태를 관리하기 위해 사용함 |
프래그먼트는 액티비티와 유사한 방식으로 동작한다. 오른쪽 사진을 보면 액티비티가 시스템 역할을 하게 되므로 액티비티 위에 올라가 있지 않은 프래그먼트는 정상적으로 동작할 수 없다.
11-2 프래그먼트를 화면에 추가하는 방법 이해하기
프래그먼트도 하나의 XML 레이아웃과 하나의 자바 소스 파일로 동작한다.
프래그먼트를 위한 자바 소스는 Fragment 클래스를 상속하여 만들 수 있다. XML 레이아웃 파일의 내용을 소스 파일과 매칭하는 과정이 필요한데, 프래그먼트에는 setContentView 메서드가 없기 때문에 인플레이션 객체인 LayoutInflater를 사용해 인플레이션을 진행해야 한다.
새로 만든 프래그먼트를 메인 액티비티에 추가하는 방법은 두 가지가 있다. 하나는 XML 레이아웃에 추가하는 것, 다른 하나는 소스 코드에서 new 연산자로 객체를 만든 후 프래그먼트 매니저로 추가하는 것이다. 두 가지 방법은 다음 내용에서 알아본다.
11-3 프래그먼트 만들어 화면에 추가하기
새로운 프로젝트를 만들고, 프래그먼트를 추가한다.
▼ 프래그먼트 인플레이션 하기
public class MainFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_main, container, false);
}
}
onCreateView 메서드를 제외한 나머지 코드는 모두 삭제한다.
inflate 메서드로 전달되는 첫 번째 파라미터는 XML 레이아웃 파일이고, 두 번째 파라미터는 이 XML 레이아웃이 설정될 뷰그룹 객체가 되는데 onCreateView 메서드로 전달되는 두 번째 파라미터가 이 프래그먼트의 가장 상위 레이아웃이다. 따라서 container 객체를 전달하면 된다. 세 번째 파라미터는 뷰그룹 객체에 뷰를 언제 설정할지 결정한다. true일 때는 지금, false일 때는 나중에 추가된다.
프래그먼트를 액티비티에 추가하는 두 가지 방법 중 이번에는 메인 액티비티의 XML 레이아웃에 태그로 프래그먼트를 추가하는 방법을 사용한다.
▼ XML 레이아웃에 프래그먼트 추가하기
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<fragment
android:id="@+id/mainFragment"
android:name="org.techtown.fragment.MainFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
11-4 버튼 클릭했을 때 코드에서 프래그먼트 추가하기
프래그먼트를 액티비티에 추가하는 두 가지 방법 중 이번에는 자바 소스 코드로 프래그먼트를 추가하는 방법을 사용한다.
▼ 메인 액티비티의 XML 레이아웃에 id 속성 값 추가하기
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
▼ 프래그먼트 인플레이션 하기
public class MainFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_main, container, false);
}
}
▼ 자바 소스 코드로 프래그먼트 추가하기
public class MainActivity extends AppCompatActivity {
MainFragment mainFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainFragment = new MainFragment();
getSupportFragmentManager().beginTransaction().add(R.id.container, mainFragment).commit();
}
}
프래그먼트 매니저는 프래그먼트를 다루는 작업을 해 주는 객체로 프래그먼트 추가, 삭제 또는 교체 등의 작업을 할 수 있게 한다. 그런데 이런 작업들은 프래그먼트를 변경할 때 오류가 생기면 다시 원래 상태로 돌릴 수 있어야 하므로 트랜잭션 객체를 만들어 실행한다. 트랜잭션 객체는 beginTransaction 메서드를 호출하면 시작되고 commit 메서드를 호출하면 실행된다.
*getSupportFragmentManager 메서드는 getFragmentManager 메서드와 같은 기능을 한다. 예전 버전까지 호환되도록 만들려면 getSupportFragmentManager 메서드를 사용하는 것이 좋다.
이제 여기에서 버튼을 클릭하면 메뉴 프래그먼트로 전환되는 기능을 추가한다.
▼ 버튼을 클릭해 프래그먼트 전환하기
public class MainActivity extends AppCompatActivity {
MainFragment mainFragment;
MenuFragment menuFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainFragment = new MainFragment();
menuFragment = new MenuFragment();
getSupportFragmentManager().beginTransaction().add(R.id.container, mainFragment).commit();
}
public void onFragmentChanged(int index){
if(index == 0){
getSupportFragmentManager().beginTransaction().replace(R.id.container, menuFragment).commit();
}else if(index == 1){
getSupportFragmentManager().beginTransaction().replace(R.id.container, mainFragment).commit();
}
}
}
메뉴 프래그먼트 객체를 선언하고, onFragmentChanged 메서드를 추가한다. onFragmentChanged 메서드는 프래그먼트에서 호출할 수 있도록 정의한 것으로, 파라미터로 전달된 정수의 값이 0이면 메뉴 프래그먼트가 보이게 하고, 1이면 메인 프래그먼트가 보이게 한다. FragmentManager 객체의 replace 메서드를 사용해 프래그먼트를 바꾸도록 입력한다.
▼ 메인 프래그먼트에서 버튼 클릭 시 onFragmentChanged 메서드 호출하기
public class MainFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_main, container, false);
Button button = rootView.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MainActivity activity = (MainActivity) getActivity();
activity.onFragmentChanged(0);
}
});
return rootView;
}
}
▼ 메뉴 프래그먼트에서 버튼 클릭 시 onFragmentChanged 메서드 호출하기
public class MenuFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_menu, container, false);
Button button = rootView.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MainActivity activity = (MainActivity) getActivity();
activity.onFragmentChanged(1);
}
});
return rootView;
}
}
11-5 프래그먼트의 수명주기
프래그먼트는 액티비티를 본떠 만들면서 액티비티처럼 독립적으로 동작하도록 수명주기(Life Cycle) 메서드를 추가했다. 프래그먼트는 액티비티 위에 올라가는 것이므로 프래그먼트의 수명주기도 액티비티의 수명주기에 종속적이지만 프래그먼트만 가질 수 있는 독립적인 상태 정보들이 더 추가되었다.
▼ 화면에 보이기 전에 호출되는 상태 메서드
메서드 | 설명 |
onAttach(Activity) | 프래그먼트가 액티비티와 연결될 때 호출됨 |
onCreate(Bundle) | 프래그먼트가 초기화될 때 호출됨 |
onCreateView(LayoutInflator, ViewGroup, Bundle) | 프래그먼트와 관련되는 뷰 계층을 만들어서 리턴함 |
onActivityCreated(Bundle) | 프래그먼트와 연결된 액티비티가 onCreate 메서드의 작업을 완료했을 때 호출됨 |
onStart() | 프래그먼트와 연결된 액티비티가 onStart되어 사용자에게 프래그먼트가 보일 때 호출됨 |
onResume() | 프래그먼트와 연결된 액티비티가 onResume되어 사용자와 상호작용할 수 있을 때 호출됨 |
▼ 중지되면서 호출되는 상태 메서드
메서드 | 설명 |
onPause() | 프래그먼트와 연결된 액티비티가 onPause되어 사용자와 상호작용을 중지할 때 호출됨 |
onStop() | 프래그먼트와 연결된 액티비티가 onStop되어 화면에서 더 이상 보이지 않을 때나 프래그먼트의 기능이 중지되었을 때 호출됨 |
onDestroyView() | 프래그먼트와 관련된 뷰 리소스를 해제할 수 있도록 호출됨 |
onDestroy() | 프래그먼트의 상태를 마지막으로 정리할 수 있도록 호출됨 |
onDetach() | 프래그먼트가 액티비티와 연결을 끊기 바로 전에 호출됨 |
액티비티와 프래그먼트의 수명주기를 알아보기 위해 각각의 메서드를 재정의한 후 로그를 출력하도록 했다. 태그 Main은 임의로 지정한 것이므로 신경 쓸 필요 없고, [M]이 MainActivity, [F]가 MainFragment에서 호출되는 메서드이다. 각각의 메서드들이 어떤 순서로 호출되는지 알아두면 좋을 것 같다.
'Android' 카테고리의 다른 글
[Do it! 안드로이드 앱 프로그래밍 #13] 액션바 사용하기 (0) | 2021.12.05 |
---|---|
[Do it! 안드로이드 앱 프로그래밍 #12] 프래그먼트로 화면 만들기 (0) | 2021.12.03 |
[Do it! 안드로이드 앱 프로그래밍 #10] 태스크 관리, 액티비티 수명주기 이해하기 (0) | 2021.11.24 |
[Do it! 안드로이드 앱 프로그래밍 #9] 인텐트, 플래그 그리고 부가 데이터 사용하기 (0) | 2021.11.21 |
[Do it! 안드로이드 앱 프로그래밍 #8] 여러 화면 만들고 화면 간 전환하기 (0) | 2021.11.19 |