Fragment 파헤치기 – 3. FragmentManager, FragmentTransaction에 대해서


저번 시간에는 Fragment LifeCycle(기억이 안나시는 분은 다시보고오자.) 에 대해서 알아 보았고, 이번 시간에는 Fragment를 실제 어떻게 Activity에서 작동 시킬 것인지에 대해서 써볼까 한다.

Fragment는 레이아웃 xml에서 바로 Add가 가능하고, 코드를 통해서는 FragmentTransaction으로 Add, Remove, Replace를 할 수있다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <fragment
        android:id="@+id/fragment"
        android:name="example.fragment"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"/>
</LinearLayout>

레이아웃 xml을 통해 아주 간단하게 Fragment를 Add할 수 있다. 한번 Add된 Fragment를 다른 Fragment로 변경 해야 되는 경우가 있는데, 이때는 FragmentTransaction을 이용해서 Action을 해야한다.

FragmentManager fragmentManager = getFragmentManager(); 

TestFragment frament = new TestFragment();  
Bundle bundle = new Bundle();   
frament.setArguments(bundle);   

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();   
fragmentTransaction.add(R.id.container, fragment); // Activity 레이아웃의 View ID    
fragmentTransaction.commit();

FragmentTransaction의 add Method를 통해서 commit할 Container View의 ID와 Fragment를 준면 된다. add는 Fragment가 계속 쌓이게 되며, replace는 하나의 Fragment가 존재하며 바꿔치기 한다. add로 Fragment를 추가 하게되면 View가 계속 쌓인 만큼 성능 또한 느려지는 점 주의하자.

Container View ID가 아닌 TAG를 통해서 UI가 없는 Background작업을 하는 Fragment를 만들 수도 있다.  또한 Dialog를 Fragment에서도 구현가능 하다.

– Activity에서의 화면 전환 처럼 setCustomAnimations()를 통해서 애니메이션이 가능하다.

findFragmentByIdfindFragmentByTag를 통해서 Commit된 Fragment를 얻어 올 수있다.

– 몇몇 상태를 제외하고 Fragment에 전달되는 이벤트들은 Atcivity에서 받은후 Fragment에 전달 되는 형태로 구성가능하다.

– Activity에서와 동일하게  onSaveInstanceState()에서 bundle에 state를 저장 후 onCreate(), onCreateView(), onActivityCreated()에서 restore 가능하다.

 

이처럼 Fragment는 활용이 아주 다양하다.

Fragment를 생성시 데이터를 넘겨줘야 하는 경우가 있는데, Fragment의 생성자로 데이터를 넘기는 경우 언제 사라질지 모르기때문에 반드시 setArguments를 통해서 사용해야된다.  

TestFragment frament = new TestFragment();  
Bundle bundle = new Bundle();   
bundle.putInt("id", 1);
frament.setArguments(bundle);

저장한 bundle을 가져올때

Bundle extra = getArguments();
int id = extra.getInt("id");

commit()은 Activity의 onSaveInstanceState() 하기전에 수행되어야 하며, 이를 어길시 java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState 예외가 발생된다.

예를 들어 화면전환을 했다가 돌아 왔을때 Fragment갱신을 해야 하는 경우를 들어 보자.

Activity1에서 onActivityCreated() → commit() 후 다른 Activity2로 전환전 Activity1의 onSaveInstanceState()가 호출 된다.  그런뒤 Activity2를 띄우고 Activity2가 닫긴후 Activity1의 onRestart() → commit()을 하면 예외가 발생한다.

onSaveInstanceState()가 된이후에 commit()을 했기때문이다.

이렇게 화면갱신이 필요한 경우에는 commit()을 쓰지 말고 commitAllowingStateLoss()를 호출 해서 onSaveInstanceState()와 무관하게 commit를 할 수 있다.

 

또한 사용하다가 주의해야 할 점은..

commit은 바로 실행 되지 않고 메인쓰레드에 의해 스케쥴처리 되기때문에 Activity는 종료 되었는데, Fragment가 생성되면서 ApplicationContext에서 NullPointException이 발생 할 수 있다.

이처럼 Fragment를 Activity에 commit하는 방법과 주의할 점에 대해서 살펴 보았다. 다음 시간에는 popBackStack과  Activity와 Fragment간의 통신방법에대해서 설명 하겠다.