Fragment 와 activity 차이점 알아보기 위해 검색하다가 찾은 정보.
* Fragment(프래그먼트) for Honeycomb
Fragment란? |
Fragment는 Activity만으로는 표현이 어려운 것들을 해결하기 위해 나온 녀석이라고 할 수 있을것 같습니다.
기존의 탭 액티비티에서 탭을 클릭하는 것이 아닌, 하나의 탭 컨텐츠 안에서 화면을 전환하기 위해서는,
ActivityGroup같은 것을 써서 Activity를 View로 만들어 사용하곤 했었습니다.
하지만 이런 경우 Decor되기 위한 View로 변환(.getDecorView())되어 버린 액티비티들은,
원래 액티비티가 가지고 있는 라이프 사이클을 완전하게 수행하지 못하게 되어버렸습니다.
그래서 Intent 플래그 중 FLAG_ACTIVITY_CLEAR_TOP 을 써서 계속해서 새로 호출하며 화면을 갱신하는 방법을 택하지 않았었나 생각되구요. (기본적으로 생성:onCreate()onDestroy()과 파괴:onDestroy()는 수행이 됨)
ActivityGroup이라는 공통의 부모가 있기는 하지만, 자식 액티비티들간의 데이터의 교환도 어려웠구요.
어쨋든 이런 문제점들과,
태블릿의 특성인 한 화면 안에서 여러개의 액티비티를 동시에 보여주는것에 적합하게 나온것이 Fragment입니다.
액티비티 대신에 Fragment라는 녀석으로 조각 조각 따로 만들어 주는 거지요.
예전 방식이 리스트를 보여주는 액티비티 A에서 뭔가를 눌렀을 때, 그 내부 컨텐츠를 보여주는 액티비티 B로 이동하는 형식이었다면, Fragment는 한번에 리스트와 컨텐츠를 동시에 한 화면에서 볼 수 있게 해 주는 것입니다.
이때 왼쪽의 리스트 부분을 하나의 fragment로, 오른쪽의 컨텐츠 부분을 다른 하나의 fragment로 구성을 해주고,
이 둘을 가지고 있는 Activity가 존재하는 것이지요.
ActivityGroup에서의 Child Activity와 비교하여 |
생각해보면, ActivityGroup과 개념이 많이 다르지 않습니다.
ActivityGroup은 Child Activity들을 View로 만들어서 화면에 보여주는 것이라면,
Honeycomb에서는 View대신에 Fragment라는 것을 사용해서 Activity와 유사한 방식의 Lifecycle을 갖는 조금 다른 뷰를 만들어내서 화면에 보여주는게 된것이죠.
Activity 기반의 Lifecycle을 가지고 있기 때문에, 실제 액티비티 하나를 운용하는것 처럼 사용하면 됩니다.
Fragment Lifecycle 관련 post http://croute.me/487 http://croute.me/491 |
Fragment는 일반 객체처럼 new 키워드를 사용해서 생성하게 됩니다.
기존에 액티비티에서 사용하는 startActivity와는 조금 다르죠.
또 한화면에 여러개의 Fragment를 동시에 보여줄 수 있기때문에, 한번에 보여지는 Fragment들간에 데이터 교환이 빈번하게 발생하게 되는데, Activity에서 하듯이 intent를 통해서 하는게 아닌, interface를 통해서 데이터를 교환하면 되기 때문에 상당히 편리해진것을 느낄 수 있습니다.
Fragment의 생성, Activity에 붙이기(Attach) |
기본적인 Honeycomb, 태블릿 UI를 구성을 생각하면, 좌측에 리스트가 보이고, 우측에 리스트에서 선택한 컨텐츠가 보이는 형식일겁니다.
간단한 예제를 만들기 위해, 아래와 같이 세개의 클래스를 만들어줍니다.
ExampleFragmentActivity extends Activity
ExampleListFragment extends Fragment
ExampleContentFragment extends Fragment
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | private static final String TAG_LIST = "LIST" ; private static final String TAG_CONTENT = "CONTENT" ; @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.example_fragment_activity); // FragmentManager를 받아온다. FragmentManager fm = getFragmentManager(); // FragmentManager를 통해 FragmentTransaction을 시작한다. FragmentTransaction ft = fm.beginTransaction(); // 왼쪽의 List로 사용할 ExampleListFragment를 생성한다. ExampleListFragment listFragment = new ExampleListFragment(); // FragmentTransaction의 replace메소드를 통해, 액티비티에 붙인다. 세번째 파라미터는 Fragment를 식별하기 위한 TAG이다. ft.replace(R.id.example_fragment_activity_ll_list_fragment, listFragment, TAG_LIST); // 오른쪽의 Content로 사용할 ExampleContentFragment를 생성한다. ExampleContentFragment contentFragment = new ExampleContentFragment(); // FragmentTransaction의 replace메소드를 통해, 액티비티에 붙인다. 세번째 파라미터는 Fragment를 식별하기 위한 TAG이다. ft.replace(R.id.example_fragment_activity_ll_content_fragment, contentFragment, TAG_CONTENT); // FragmentTransaction을 통해 Fragment에 대한 변경사항을 적용한다. ft.commit(); } |
생성은 일반적인 자바 객체를 생성하듯 new 를 사용해서 생성해줍니다. // 왼쪽의 List로 사용할 ExampleListFragment를 생성한다. ExampleListFragment listFragment = new ExampleListFragment(); |
액티비티에 붙이는 건, FragmentTransaction의 replace메소드를 이용합니다. // FragmentTransaction의 replace메소드를 통해, 액티비티에 붙인다. ft.replace(R.id.example_fragment_activity_ll_list_fragment, listFragment, TAG_LIST); |
Activity로부터 Fragment 가져오기 |
Activity의 어느 메소드라도, Fragment를 액티비티에 붙인 이후에는,
아래와 같은 코드를 통해 Activity에 붙어있는 Fragment를 가져올 수 있습니다.
이때 String tag를 사용해서 가져올 수 있습니다.
태그는 위에서 액티비티에 프래그먼트를 붙일 때 사용했던 태그입니다.
1 | ExampleListFragment listFragment = (ExampleListFragment) getFragmentManager().findFragmentByTag(TAG_LIST); |
Fragment의 onCreateView(LayoutInflater, ViewGroup, Bundle) |
아래의 코드는 ExampleListFragment의 onCreateView 메소드 입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View convertView = inflater.inflate(R.layout.example_list_fragment, null ); ListView listView = (ListView) convertView.findViewById(R.id.example_list_fragment_lv_list); listView.setOnItemClickListener( this ); articleList = new ArrayList<Article>(); articleListAdapter = new ArticleListAdapter(getActivity(), R.layout.example_list_fragment_row, articleList); listView.setAdapter(articleListAdapter); return convertView; } |
메소드 내의 첫번째 줄과 마지막 줄을 제외하고 본다면, 일반적으로 액티비티의 onCreate 메소드에서 사용하는 것과 같은 방식으로 사용할 수 있습니다.
주의할점은 만든 View 객체를 return 해주는것 정도입니다.
글이 너무 길어져서 이정도로 끝내야겠네요.
다음에는 interface를 사용해서 Fragment와 Activity간의 데이터 교환, Fragment - Activity - Fragment의 데이터교환에 관련된 내용과, ActionBar에 대해서 다뤄보도록 하겠습니다.
* 프래그먼트에 대해서
출처 : http://developer.android.com/guide/topics/fundamentals/fragments.html
- Fragment 는 Activity에 포함 가능한 sub activity로 볼 수 있는데, Activity 의 life cycle 과 비슷한 cycle 을 타고 간다. Fragment 도 Activity 처럼 extends 를 해서 작성 및 사용한다.
- Fragment 는 Xml 에서도 정의 가능한데 <fragment> 태그를 사용한다.
- Fragment 는 Back Stack 을 가지고 있다. 이것은 system 에서 관리해주는 activity back stack 과는 다르며, activity 에 유지되는, programmer 가 관리하는 back stack 이다.
- Fragment 의 life cycle 중 onCreate(), onCreateView(), onPause() 는 거의 반드시 기술한다. onCreate 는 생성시, onCreateView 는 View 최초 생성시 호출되며, onCreateView는 fragment의 root view 를 return 한다. onPause 는 activity life cycle 의 onPause 와 비슷하다.
- Fragment 의 sub class 들은 DialogFragment, ListFragment, PreferenceFragment 들이 있다.
- system 이 fragment 를 restore 할 때 ( 예를 들면 activity 의 restart ), fragment 들을 구분하기 위해서 fragment 에 id 를 부여해야 한다. 3가지 방법이 있는데, android:id 로 unique ID 를 주던가, android:tag 로 unique String 을 주면 된다. 둘 다 주지 않으면, system 이 container view 의 ID 를 사용한다.
- fragment 를 add, remove, replace 할 때는 "반드시" FragmentTransaction API 를 사용해야만한다. 다음과 같은 방법으로 해준다.
FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment); // first param is viewgroup id.
fragmentTransaction.commit();
- fragment 를 UI 가 없는 녀석으로 만들어 background 작업을 하도록 사용할 수도 있다. 이때는 add( Fragment fragment, String tag ) 를 통해 등록을 한다. 이렇게 등록을 하면 onCreateView() 가 호출되지 않는다. 물론 구현할 필요도 없다. 등록시의 tag 는 findFragmentByTag() 를 통해 해당 fragment 에 접근하는데 쓰인다.
- FragmentManager 를 통해서 fragment 를 control 하는데 다음과 같은 일들을 할 수 있다.
1. findFragmentById 나 findFragmentByTag 를 통해서 fragment 를 얻어올 수 있다.
2. popBackStack() 을 통해 Activity 에서 BackKey 를 누른 것과 비슷한 효과를 낼 수 있다.
3. addOnBackStackChangedListener 를 통해 listener 등록도 가능하다.
4. FragmentTransaction 을 얻어 operation 을 할수도 있다.
- FragmentTransaction 을 통해, add(), remove(), replace(), commit() 등을 호출 가능하고, addToBackStack() 을 통해 activity 에서 관리하는 back stack 에 FragmentTransaction 을 등록 가능하다. BackKey 가 눌렸을 때 back stack 이 작동한다.
- fragment 가 addTobackStack() 을 통해 remove 되는 경우는 stopped state 에 들어가고, 그렇지 않을 경우에는 destory state 로 들어간다.
- commit() 전에 setTransition() API 를 통해, transition animation 을 줄 수 있다.
- commit() 된 transaction 은 바로 실행되지 않고, main thread 에 schedule 되어 처리된다.executePendingTransaction() 을 통해 commit() 된 녀석을 바로 실행시킬 수 있지만, 다른 thread 와의 work 에 dependency 가 있지 않는 한은 쓸 일이 없을 것이다.
- commit() 은 activity 가 state save 하기 전에 이루어져야 한다. state save 후에 commit() 이 불린다면 exception 이 발생한다. 만약 state save 와 관계없이, fragement 의 state 저장과 관련없게 작동하게 하려면 commit() 대신 commitAllowingStateLoss() 를 호출해줘야 한다.
- Fragment 에서 option menu를 구성하려면 onCreate() 에서 setHasOptionsMenu() 를 call 해주어야 한다. 그렇지 않으면, fragment의 onCreateOptionsMenu() 가 불리지 않는다. 마찬가지로, menu item 이 click 되면 onOptionsItemSelected() 가 호출된다.
- fragment 에도 registerForContextMenu() API 가 있으며, context menu 생성시 onCreateContextMenu() 가 불리고, item click 시 onContextItemSelected() 가 불린다.
- Fragment 에 전달되는 event 들은 사실 activity 가 먼저 받고, 그 다음에 fragment 에 전달이 되는 형태이다. 물론 activity 에서 다 처리하고, fragment 로 전달하지 않도록 하는 방법도 있다.
- fragment 도 bundle 에 state 를 저장할 수 있다. fragment 의 onSaveInstanceState() 에서 저장하고, onCreate(), onCreateView() 혹은 onActivityCreated() 에서 restore 해주면 된다.
'클라이언트 > Android' 카테고리의 다른 글
termux에서 ubuntu 환경 만들기 (0) | 2022.07.01 |
---|---|
[Android] UI Code Eaxple (0) | 2015.11.12 |
Practice Diary (0) | 2014.08.27 |
[GoogleMap] code Google API 정리 (0) | 2013.10.11 |
[GoogleMap] 개발 관련 이미지 자료 (0) | 2013.10.03 |