화면의 일부분을 다른 화면으로 구성하고 싶을 떄는 어떻게 해야 할까요?
즉, 전체 화면 안에 부분 화면을 만들어 넣으면 화면을 전환하지 않아도 되니 불편하지도 않고 넓은 화면을 잘 활용할 수 있어 좋습니다.
화면을 여러 부분으로 나눠서 보여주거나 각각의 부분 화면 단위로 바꿔서 보여주고 싶을 때 사용하는 것이 프래그먼트(Fragement)입니다. 프래그먼트는 태블릿처럼 큰 화면의 단말을 지원하려고 시작했는데 지금은 단말의 크기와 상관없이 화면 UI를 만들 때 많이 사용됩니다.
프래그먼트 사용 목적
- 분할된 화면들을 독립적으로 구성하기 위해 사용함.
- 분할된 화면들의 상태를 관리하기 위해 사용함.
프래그먼트가 화면 분할을 위한 것이라면, 액티비티의 화면과 구별할 수 있어야 합니다.
프래그먼트가 화면 분할을 위한 것이라고 얘기할 때 사용하는 '화면'이라는 말과 액티비티에서 사용하는 '화면'이라는 말은 서로 다른 것을 가리킵니다. 똑같이 XML 레이아웃으로 만들지만 액티비티에 사용되면 시스템에서 관리하는 화면이고, 프래그먼트에서 사용되면 단순히 액티비티 위에 올라가는 화면의 일부, 즉 '부분 화면'이 됩니다.
프래그먼트는 항상 액티비티 위에 올라가 있어야 한다는 점입니다. 액티비티로 만든 화면을 분할한 뒤 각각의 부분 화면을 프래그먼트로 만들고 그 프래그먼트를 독립적으로 관리하는 것이 목표이기 때문에 프래그먼트는 액티비티 위에 올라가 있어야 프래그먼트로서의 역할을 할 수 있습니다. 따라서 프래그먼트가 재대로 동작하는 시점은 프래그먼트가 메모리에 만들어진 시점이 아니라 액티비티에 올라가는 시점입니다.
액티비티는 앱 구성 요소이므로 안드로이드 시스템에서 관리합니다. 좀 더 구체적으로는 액티비티 매니저가 액티비티의 동작 순서나 처리 방식을 결정합니다. 또한 액티비티가 시스템에서 관리되기 떄문에 시스템이 이해하는 형식으로 명령이나 테이블을 만들어 보내야 하는데, 인텐트가 그 역활을 합니다. 다시 말해, 액티비티를 관리하는 시스템 객체는 액티비티 매니저이며, 이 액티비티 매니저에 의해 액티비티가 독립적으로 동작할 수 있습니다.
액티비티가 동작하는 왼쪽 방식을 그대로 본떠 만들었다는 것을 알 수 있습니다. 왼 쪽 그림에서 안드로이드 시스템이 하던 역할을 오른쪽 그림에서는 액티비티가 합니다. 왼쪽 그림에서 액티비티 매니저가 액티비티들을 관리했다면 오른쪽 그림에서는 프래그먼트 매니저라는 것을 만들어 프래그먼트들을 관리하도록 했습니다. 여기에서 보면 프래그먼트가 액티비티가 시스템 역할을 하게 되므로 액티비티 위에 올라가 있지 않은 프래그먼트는 정상적으로 동작할 수 없다는 점을 짐작할 수 있습니다.
인텐트가 하던 역할을 프래그먼트에서는 사용할 수 없습니다. 왜냐하면 인텐트는 시스템에서 이해하는 객체인데 그것을 프래그먼트와 액티비티 사이에서 전달하게 만드는 것은 바람직하지 않기 때문입니다. 이 때문에 액티비티와 프래그먼트 간에 데이터를 전달할 때는 단순히 메서드를 만들고 메서드를 호출하는 방식을 사용합니다.
프래그먼트는 액티비티 위에 항상 두 개 이상이 올라가 있어야 할까요? 그렇지 않습니다 .하나으 ㅣ프래그먼트만 액티비티에 올련놓아도 상관 없습니다. 그리고 그 프래그먼트가 화면 전체를 채우도록 할 수 있어 사용자는 프래그먼트가 하나의 전체 화면처럼 느끼게 됩니다. 이런 방식을 사용하면 원하는 시점에 하나의 프래그먼트를 올려놓았다가 다른 프래그먼트로 바꿔서 보여줄 수도 있으므로 액티비티를 전환하지 않아도 화면 전환 효과를 낼 수 있습니다.
액티비티는 시스템에서 관리하지만 프래그먼트는 액티비티 위에 올라가 있어 액티비티를 전환하지 않고도 훨씬 가볍게 화면 전환 효과를 만들 수 있게 됩니다. 특히 탭 모양으로 화면을 구성할 때 각각의 [탭] 버튼을 클릭할 대마다 다른 화면이 보이는 효과를 내고 싶디면 액티비티가 아닌 프래그먼트를 사용하는 것이 좋습니다.
프래그먼트를 화면에 추가하는 방법 이해하기.
플래그먼트 사용 목적은 부분 화면을 독립적으로 사용하기 위해서이고 액티비티를 본떠 만든 것이라고 했습니다. 이 떄문에 프래그먼트를 만들 때 액티비티를 만들 떄의 과정과 비슷하게 진행합니다. 즉, 액티비티라는 것이 하나의 XML 레이아웃과 하나의 자바 소스 파일로 동작하는 것처럼 프래그먼트도 하나의 XML 레이아웃과 하나의 자바 소스 파일로 동작하게 만듭니다.
다음은 프래그먼트 클래스에 있는 주요 메서드입니다.
[CODE]
public final Activity getActivity()
-> 이 프래그먼트를 포함하는 액티비티를 반환함
public final FragmentManager getFragmentManager()
-> 이 프래그먼트를 포함하는 액티비티에서 프래그먼트 객체들과 의사소통하는 프래그먼트 매니저를 반환함.
public final Fragment getParentFragment()
-> 이 프래그먼트를 포함하는 부모가 프래그먼트일 경우 리턴함. 액티비티이면 null을 반환함.
public final int getId()
-> 이 프래그먼트의 ID를 반환함.
프래그먼트를 위한 클래스 까지 만들었다면 XML 레이아웃 파일의 내용을 소스 파일과 매칭하는 과정이 필요합니다. 그런데 플래그먼트에는 setContentView() 메서드가 없습니다. 그래서 인플레이션 객체인 LayoutInflater를 사용해 인플레이션을 진행해야 합니다. XML 레이아웃 파일의 내용을 인프레이션한 후 클래스에서 사용하도록 하는 코드는 onCreateView() 메서드 안에 들어갑니다. onCreate-View()메서드는 콜백 메서드로 인플레이션이 필요한 시점에 자동으로 호출됩니다. 따라서 이 메서드안에서 인플레이션을 위한 inflate() 메서드를 호출하면 되고 인플레이션 과정이 끝나면 프래그먼트가 한의 뷰처럼 동작할 수 있는 상태가 됩니다.
프래그먼트는 버튼이나 레이아웃처럼 화면을 일정 공간을 할당받을 수 있으므로 새로 만든 프래그먼트를 메인 액티비티에 추가하는 방법은 뷰가 마찬가지로 XML 레이아웃에 추가하거나 또는 소스 코드에서 new 사용자로 객체를 만든 후 프래그머먼트 매니저로 추가할 수 있습니다.
메인 액티비티의 레이아웃 파일인 activity_main.xml 파일에 프래그먼트를 추가하면 프래그먼트 화면이 액티비티에 추가됩니다. 만약 코드에서 프래그먼트를 추가하고 싶다면 프래그먼트 관리를 담당하는 프래그먼트 매니저를 사용해야 합니다. 프래그먼트 매니저(FrageMentManger) 클래스에 들어 있는 주요 메서드들은 다음과 같습니다.
[Code]
public abstract FragmentTransaction beginTRANSACTION()
-> 프래그먼트를 변경하기 위한 트랜잭션을 시작함.
public abstract Fragment findFragmentById(int id)
-> ID를 이용해 프래그먼트 객체를 찾음.
public abstract Fragment findFragmentByTag (String tag)
-> 태그 정보를 사용해 프래그먼트 객체를 찾음.
public abstract boolean executePendingTransactions ()
-> 트랜잭션은 commit() 메서드를 호출하면 실행되지만 비동기(asynchronous) 방식으로
실행되므로 즉시 실행하고 싶다면이 메서드를 추가로 호출해야 함.
FragmentManager 객체는 프래그먼트를 액티비티에 추가(add), 다른 프래그먼트로 바꾸거나(re-place) 또는 삭제(remove)할 때 주로 사용할 수 있으며 getFragmentManager() 메서드를 호출하면 참조할 수 있습니다.
getSupportFragmnetManager() 메서드가 getFragmentManager() 메서드와 같은 기능을 한다
프래그먼트 매니저 객체를 참조하려면 getFragmentManager() 메서드를 호출할 수도 있고 getSupportFragmnet-Manager() 메서드를 호출할 수도 있습니다 .이것은 이전 버전의 단말에서도 동작할 수 있도록 appcompat 라이브러리(Android Compatibilityt Liblrary)의 기능을 사용하기 때문입니다. 일반적인 경우에는 예전 버전까지 호환되도록 만드는 것이 좋으므로 getSupportFragmentManager() 메서드를 사용하는 것을 권장합니다.
프래그먼트는 다음과 같은 특성을 가지고 있으며, 큰 화면과 해상도를 가진 태블릿의 경우에 더욱 유용하게 사용될 수 있습니다.
| 특성 | 설 명 | |
| 뷰 특성 | 뷰그룹에 추가 되거나 레이아웃의 일부가 될 수 있음 (뷰에서 상속받은 것은 아니며 뷰를 담고 있는 일종의 틀임) |
|
| 액티비티 특성 | 액티비티처럼 수명주기(Lifecycle) 가지고 있음 (컨텍스트 객체는 아니며 라이프사이클은 액티비티에 종속됨) |
|
프래그먼트 클래스는 보통 Fragment 클래스를 상속하도록 만들지만 프래그먼트 중에는 미리 정의된 몇 가지 프래그먼트 클래스들이 있어 그 클래스를 그대로 사용할 떄도 있습니다. 그중에서 DialogFrag-ment는 액티비티의 수명주기에 의해 관리되는 대화상자를 보여줄 수 있도록 합니다. 이 프래그먼트는 액티비티의 기본 대화상자 대신 사용할 수 있습니다.
프래그먼트 화면에 만들어 추가하기.

[New -> Fragment -> Fragment(Blank)] 를 선택해서 새로운 플래그먼트를 추가합니다.
Fragment_main.xml 파일과 MainFragment.Java 파일이 새로 추가됩니다. 프래그먼트도 화면에 표시되는 구성 요소이기 때문에 화면 레이아웃을 구성하는 XML 파일과 기능을 담당하는 소스 파일이 한쌍으로 만들어진 것 입니다.
public class MainFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public MainFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment MainFragment.
*/
// TODO: Rename and change types and number of parameters
public static MainFragment newInstance(String param1, String param2) {
MainFragment fragment = new MainFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_main, container, false);
}
}
프래그먼트를 구성할 XML 레이아웃 파일을 만들었으니 이제 소스 코드를 확인합니다. MainFrag_ment.java 파일의 코드 입니다. 그중에서 우리는 onCrewateView 메서드를 살펴봅니다.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_main, container, false);
}
onCreateView() 메서드의 파라미터로 LayoutInflater 객체가 전달되므로 이 객체의 inflate() 메서드를 바로 호출할 수 있습니다. inflate() 메서드로 전달되는 첫 번째 파라미터는 XML 레이아웃 파일이 되므로 R.layout.fragment_main이 입력되어 있습니다. 두 번째 파라미터는 이 XML 레이아웃이 설정 될 뷰 그룹 객체가 되는데 onCreateView() 메서드로 전달되는 두 번째 파라미터가 이 프래그먼트의 가장 상위 레이아웃 입니다. 따라서 container 객체르 전달하면 됩니다. inflate() 메서드를 호출하면 인플레이션이 진행되고 그 결과로 ViewGroup 객체가 반환됩니다. 이 객체를 return 키워드를 사용하여 반환합니다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".MainActivity">
<fragment
android:id="@+id/mainFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="org.techtown.fragment.MainFragment"
/>
</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity 를 실행했을 떄 결과입니다. 다음과 같이 MainActivity 안에 Fragment 가 실행되는 것을 확인할 수 있습니다.
프래그먼트의 수명 주기
프래그먼트는 액티비티를 본떠 만들면서 액티비티처럼 독립적으로 동작하도록 수명주기(Life Cycle) 메서드를 추가했습니다. 따라서 상태에 따라 API에서 미리 정해둔 콜백 함수가 호출되므로 그 안에 필요한 기능을 넣을 수 있습니다. 프래그먼트를 사용하는 목정 중의 하나가 분할된 화면들의 상태를 관리하는 것인데 이것을 가능하게 하는 것이 수명주기 메서드들입니다 .즉, 액티비티 안에 들어 있는 프래그먼트도 필요할 때 화면에 보이거나 보이지 않게 되므로 액티비티처럼 각각의 상태가 관리되는 것이 필요합니다.
프래그먼트는 액티비티 위에 올라가는 것이므로 프래그먼트의 수명주기도 액티비티의 수명주기에 종속적이지만 프래그먼트만 가질 수 있는 독립적인 상태 정보들이 더 추가되었습니다. 특히 프래그먼트가 화면에 보이기 전이나 중지 상태가 되었을 때 액티비티 처럼 onResume() 메서드와 onPause() 메서드가 호출되는데 프래그먼트는 액티비티에 종속되어 있으므로 이 상태 메서드 이외에도 세분화된 상태 메서드들이 더 있습니다.
다음은 화면에 보이기 전에 호출되는 상태 메서드 입니다.
| 메서드 | 설 명 |
| onAttach(Activity) | 프래그먼트가 액티비티와 연결될 때 호출됨. |
| onCreate(Bundle) | 프래그먼트가 초기화될 때 호출됨 (new 연산자를 이용해 새로운 프래그먼트 객체를 만드는 시점이 아니라는 점에 주의해야 함) |
| onCreateView(LayoutLnflater, ViewGroup, Bundle) | 프래그먼트와 관련되는 뷰 계층을 만들어서 리턴함. |
| onActivityCreated(Bundle) | 프래그먼트와 연결된 액티비티가 onCreate() 메서드의 작업을 완료했을 때 호출됨. |
| onStart() | 프래그먼트와 연결된 액티비티가 onStart()되어 사용자에게 프래그먼트가 보일 떄 호출됨. |
| onResume() | 프래그먼트가 연결된 액티비티가 onResume()되어 사용자가 상호작용할 수 있을 때 호출됨. |
다음은 프래그먼트가 화면에서 보이지 않게 되면서 호출되는 상태 메서드 들입니다.
| 메서드 | 설명 |
| onPuase() | 프래그먼트와 연결된 액티비티가 onPause()되어 사용자와 상호작용을 중지할 때 호출됨. |
| onStop() | 프래그먼트와 연결된 액티비티가 onStop()되어 화면에서 더 이상 보이지 않을 때나 프래그 먼트의 기능이 중지 되었을 때 호출됨. |
| onDestroyView() | 프래그먼트와 관련된 뷰 리소스를 해체할 수 있도록 호출됨. |
| onDestroy() | 프래그먼트와 상태를 마지막을 정리할 수 있도록 호출됨. |
| onDetach() | 프래그먼트와 액티비티와 연결을 끊기 바로 전에 호출됨. |
'안드로이드' 카테고리의 다른 글
| RecyclerView로 동적 목록 만들기 (0) | 2021.10.15 |
|---|---|
| View 와 ViewGroup 이해하기 (0) | 2021.06.04 |
| Crashlytic (0) | 2021.04.16 |
| Activity 상태 및 메모리에서 제거 (0) | 2021.04.12 |
| 안드로이드 생명주기 (0) | 2021.04.09 |
