* 프래그먼트(Fragment) 이해
동일한 레이아웃을 한 번만 정의하고, 여러군데에서 재사용할 수 있도록 하는 것이 '프래그먼트' 이다.
프래그먼트는 태블릿처럼 큰 화면의 단말을 지원하려고 시작했는데, 지금은 단말의 크기와 상관없이 화면 UI를 만들 때 많이 사용된다.
프래그먼트는 하나의 화면 안에 들어가는 부분 화면과 비슷한데, 그런 의미에서는 레이아웃처럼 보이나, 실제론 액티비티처럼 독립적으로 동작하는 부분 화면이다.
프래그먼트의 사용 목적은 분할된 화면들을 독립적으로 구성하기 위해 사용하며,
분할된 화면들의 상태를 관리하기 위해 사용한다.
분할된 화면들의 상태를 관리하기 위해 사용한다.
액티비티의 레이아웃은 시스템이 관리하지만, 프래그먼트에서 사용되는 레이아웃은 단순한 부분화면으로서 액티비티의 구성요소일 뿐이다.
프래그먼트는 항상 액티비티 위에 올라가 있어야 제대로 동작하게 된다.
액티비티로 만든 화면을 분할한 뒤 각각의 부분 화면을 프래그먼트로 만들고 그 프래그먼트를 독립적으로 관리하는 것이 목표이기 때문에 프래그먼트는 액티비티 위에 올라가 있어야 프래그먼트로서의 역할을 할 수 있다.
즉 프래그먼트가 메모리에 올라간 시점이 아닌 액티비티에 올라가는 시점이 프래그먼트가 제대로 동작하는 시점이라고 할 수 있다.
프래그먼트로 구성된 대표적인 위젯으로 뷰페이저와 바로가기 메뉴가 있다.
* 프래그먼트가 동작하는 방식
프래그먼트는 액티비티의 동작방식을 본 떠 만들었다.
액티비티 동작방식은 액티비티 매니저가 액티비티의 동작 순서나 처리 방식을 결정한다.
또한 액티비티가 시스템에서 관리되기 때문에 시스템이 이해하는 형식으로 명령이나 데이터를 전달하는 역할을 인텐트가 한다.
즉, 액티비티를 관리하는 시스템 객체는 액티비티 매니저이며, 이 액티비티 매니저에 의해 액티비티가 독립적으로 동작할 수 있게 된다.
프래그먼트는 이러한 액티비티 동작방식과 유사하게 만들어졌다.
액티비티 동작방식에서 시스템이 하는 역할을 액티비티가 하게 되고, 프래그먼트를 관리하는 프래그먼트 매니저가 있다.
고로 액티비티가 시스템 역할을 하므로 프래그먼트는 액티비티 위에 올라가 있지 않으면 정상동작할 수 없다.
인텐트가 하던 역할은 프래그먼트에서는 사용할 수 없다. 왜냐하면 인텐트는 시스템에서 이해하는 객체인데 그것을 프래그먼트와 액티비티 사이에서 사용할 수 없기 때문이다.
액티비티와 프래그먼트 간에 데이터를 전달할 때는 단순히 메서드를 만들고 메서드를 호출하는 방식을 사용한다.
하나의 액티비티에서 프래그먼트만 전환하게 하면 가벼운 화면 전환 효과를 얻을 수 있다.
또한 프래그먼트도 액티비티를 만들 때의 과정과 비슷하게, 하나의 XML 레이아웃과 하나의 자바소스 파일로 동작하게 된다.
* 액티비티에 프래그먼트 넣고 프래그먼트->프래그먼트로 교체해보기
아래 이미지의 경로로 진입하여 MainFragment와 MenuFragment 2개를 생성한다.
* MainFragment.java
* MainActivity.java
* MenuFragment.java
* 프래그먼트의 수명주기
프래그먼트들도 액티비티와 같이 수명주기가 있다.
프래그먼트들의 상태를 관리하는 것이 필요하기 때문이다.
- 액티비티에 프래그먼트 추가시
onAttach -> onCreate -> onCreateView -> onActivityCreated -> onStart -> onResume
* 액티비티에 프래그먼트 넣고 프래그먼트->프래그먼트로 교체해보기
아래 이미지의 경로로 진입하여 MainFragment와 MenuFragment 2개를 생성한다.
[File] -> [Fragment] -> [Fragment (blank)] 클릭 |
메인 액티비티 레이아웃에 위와 같이 태그로 새로 만든 fragment를 추가한다. id는 mainFragment로 지정한다. name은 MainFragment.java의 패키지 경로를 포함하여 이름까지만 입력해야 한다. |
메인프래그먼트 레이아웃은 텍스트뷰와 버튼을 하나 만들었고, 버튼을 클릭했을 때 메뉴화면(메뉴프래그먼트)로 프래그먼트 전환이 일어나도록 할 것이다. |
* MainFragment.java
public class MainFragment extends Fragment {
@Override
// 프래그먼트와 관련되는 뷰 계층을 만들어서 리턴한다.
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// rootView : 인플레이션을 통해 참조한 최상위 레이아웃
// 최상위 레이아웃은 메인 프래그먼트 안에 들어있고,
// 메인 프래그먼트는 이 레이아웃을 화면에 보여주기 위한 틀이다.
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_main,
container, false);
// 따라서 rootView를 통해 findViewBytId()을 이용하여 버튼 객체를 참조한다.
Button button = rootView.findViewById(R.id.button);
// 버튼을 클릭했을 때 메뉴프래그먼트 화면으로 전환이 되어야 한다.
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 메인 액티비티 객체를 참조한다.
MainActivity activity = (MainActivity) getActivity();
// onFragmentChanged 메소드는 메인액티비티에 존재하는 메서드이다.
// 프래그먼트 매니저를 이용해 프래그먼트를 전환하는 메서드이다.
// 하나의 프래그먼트에서 다른 프래그먼트를 띄우려면 액티비티를 통해 띄어야 하므로
// 메인 액티비티 코드 쪽에 아래의 메서드가 위치해야한다.
activity.onFragmentChanged(0);
}
});
return rootView;
}
}
* MainActivity.java
public class MainActivity extends AppCompatActivity {
MainFragment mainFragment;
MenuFragment menuFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//프래그먼트는 뷰가 아니라서 바로 찾을 수 없고 프래그먼트매니저를 통해 객체를 참조할 수 있다.
mainFragment = (MainFragment) getSupportFragmentManager().findFragmentById(R.id.mainFragment);
menuFragment = new MenuFragment();
}
//실제로 액티비티에 프래그먼트를 추가하고 프래그먼트로 동작하게 되는 메소드
//프래그먼트는 액티비티가 관리하여야 하므로 메서드 기능상 MainActivity.java 쪽에 있는 것이 낫다.
public void onFragmentChanged(int index){
//index가 0이면 메뉴프래그먼트로 교체함
if(index == 0){
//트랜젝션을 시작하고 프래그먼트를 교체한 후에 commit()을 호출하여 실제로 트랜젝션이 실행된다.
//프래그먼트 화면 교체 중에 오류가 발생하면 트랜젝션 이전의 상태로 되돌리게 하기 위함이다.
getSupportFragmentManager().beginTransaction().replace(R.id.container, menuFragment).commit();
//index가 1이면 메인프래그먼트로 교체함
}else if(index == 1){
getSupportFragmentManager().beginTransaction().replace(R.id.container, mainFragment).commit();
}
}
}
* MenuFragment.java
public class MenuFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// fragment_menu.xml 레이아웃 파일의 내용이 인플레이션 되어야 하므로 아래와 같이 입력
return inflater.inflate(R.layout.fragment_menu, container, false);
}
}
* 프래그먼트의 수명주기
프래그먼트들도 액티비티와 같이 수명주기가 있다.
프래그먼트들의 상태를 관리하는 것이 필요하기 때문이다.
- 액티비티에 프래그먼트 추가시
onAttach -> onCreate -> onCreateView -> onActivityCreated -> onStart -> onResume
- onAttach(Activity) : 프래그먼트가 액티비티와 연결할 때 호출됨
- onCreate(Bundle) : 프래그먼트가 초기화 할 때 호출됨. new 연산자를 이용해 새로운 프래그먼트 객체를 만드는 시점이 아니라는 것에 주의
- onCreateView(LayoutInflator, ViewGroup,Bundle) : 프래그먼트와 관련되는 뷰 계층을 만들어서 리턴함
- onActivityCreated(Bundle) : 프래그먼트와 연결된 액티비티가 onCreate() 메서드의 작업을 완료했을 때 호출함
- onStart() : 프래그먼트와 연결된 액티비티가 onStart()되어 사용자에게 프래그먼트가 보일 때 호출 됨
- onResume() : 프래그먼트와 연결된 액티비티가 onResume()되어 사용자와 상호작용할 수 있을 때 호출됨
onAttach() 메서드가 호출될 때 파라미터로 전달되는 액티비티 객체 위에 프래그먼트가 올라가 있게 된다. 그러므로 액티비티를 위해 설정해야 하는 정보들은 이 onAttach() 메서드에서 처리해야 한다.
- 액티비티에 프래그먼트 제거시
onPause -> onStop -> onDestroyView -> onDestroy -> onDetach
- onPause : 프래그먼트와 연결된 액티비티가 onPause()되어 사용자와 상호작용을 중지할 때 호출됨
- onStop : 프래그먼트와 연결된 액티비티가 onStop()되어 화면에서 더 이상 보이지 않을 때나 프래그먼트의 기능이 중지되었을 때 호출됨
- onDestroyView : 프래그먼트와 관련된 뷰 리소스를 해제할 수 있도록 호출됨
- onDestroy : 프래그먼트의 상태를 마지막으로 정리할 수 있도록 호출됨
- onDetach : 프래그먼트가 액티비티와 연결을 끊기 바로 전에 호출됨
MenuFragment fragment = new MenuFragment();
// 프래그먼트 객체는 만들어졌지만 프래그먼트로 동작하지는 않음
getSupportFragmentManager().beginTransaction().add(fragment).commit();
// 액티비티에 추가된 후 프래그먼트로 동작함
댓글 없음:
댓글 쓰기