인쇄하기 인쇄 [22 장 ] 프래그먼트 (1/8) (20140815 완료 ) 책에담지못한장들 슈퍼성근 조회 326 2014/08/10 22:38:46 주의 : 소스내용중 "0nClick", "0nStart" 함수명첫글자가숫자 0 인것은오타가아닙니다. 다움게시판은 o n C l i c k 라는글을입력할수없기때문에어쩔수없이 영문소문자 o 를숫자 0 으로대체하였습니다. ^^; 22 장프래그먼트 프래그먼트를간단히한줄로설명하자면, 액티비티내의작은액티비티라할수있다. 그말은프래그먼트는 UI 와 라이프사이클을가지고있는독립적인모듈이라는의미다. 그러나독립적으로실행될수없고액티비티에포함되어 사용된다는점은액티비티와다른점이다. [ 그림 22 1] 을살펴보자. 그림 22 1 프래그먼트 1 프래그먼트는액티비티와같이자신만의레이아웃을포함하고, 별도의생명주기함수도가진다. 이단위 는매우유연하고독립적이어서다른액티비티에포함될수도있다. 2, 3 과같이특정액티비티는여러프래그먼트를조합하여화면을구성할수있다. [ 그림 22 1] 과같이프래그먼트단위의조합으로만들어진액티비티는복잡도가낮고유지보수가용이하다. 즉프래그먼트단위로레이아웃과자바소스파일이분리되기때문이다. 여기까지보자면프래그먼트는안드로이드의필수적인요소라고느껴질수있다. 하지만프래그먼트는안드로이드 API 11 허니콤부터추가되었고, 그전까지프래그먼트가없어도앱을구현하는데문제는없었다. 아니좀더정확히표현하자면프래그먼트를대신할수있는다른요소들을이용했다고하는것이맞다. 그래서프래그먼트를정확히이해하려면 [ 그림 22 2] 과같이프래그먼트이전의기술들을차례대로살펴보는것이중요하다. http://cafe.daum.net/_c21_/bbs_print?grpid=1mwa2&mgrpid=&fldid=pgqt&dataid=4 1/10
그림 22 2 뷰와뷰그룹에서프래그먼트까지 1 레이아웃은뷰와뷰그룹요소만으로도원하는화면과그에대한처리를모두할수있다. 2 하지만 include 레이아웃요소를이용하면좀더화면을유연하게구성할수있도록돕는다. 3 하지만 ActivityGroup 를이용하면여러개의액티비티를포함할수있기때문에훨씬강력한방법으로화 면을유연하고독립적으로구성할수있다. 4 하지만프래그먼트를이용하면 ActivityGroup 보다완벽한방법으로화면을유연하고독립적으로구성할 수있다. 참고로프래그먼트는 ActivityGroup 의문제점들은해결하기위해등장했다. 즉프래그먼트는 ActivityGroup 를대체하기위해탄생한것이다. [ 그림 22 2] 에나열된기술의흐름은너무자연스러워그필요성을느끼는데전혀어렵지않다. 가벼운마음으로시 작해보자. [ 이장의실습내용 ] 1 2 3 4 뷰와뷰그룹만을이용하기에는불편한레이아웃 XML 레이아웃 XML 요소 include 활용 ActivityGroup 활용프래그먼트활용 22.1 레이아웃 XML 요소 include 레이아웃 XML 의 include 요소는특정레이아웃을다른레이아웃안으로포함시킬수있도록한다. 따라서여러레이 아웃에중복적으로들어가는부분의레이아웃을따로빼서별도의레이아웃리소스파일을만들고, 필요한레이아 웃에 include 요소를이용하여추가하면된다. 먼저 include 요소의필요성을예제를통해느껴보자. 22.1.1 뷰와뷰그룹을이용한일반적인레이아웃 일반적인 [ 그림 22 3] 과같은레이아웃을구성해보는과정에서불편한요소를찾아보자. 그림 22 3 일반적인레이아웃구조 1 A 액티비티는상단에부제목텍스트와메뉴, 종료버튼으로구성된부제목영역이존재하고그하단에는 액티비티의콘텐트영역의레이아웃이배치된다. 그리고가장하단에는 B 액티비티를실행할수있는버튼 이존재한다. http://cafe.daum.net/_c21_/bbs_print?grpid=1mwa2&mgrpid=&fldid=pgqt&dataid=4 2/10
2 B 액티비티역시상단에 A 액티비티와같은부제목영역이존재하고하단에는액티비티의콘텐트영역의 레이아웃이배치된다. 새로운예제패키지를생성하고다음과같이 AndroidManifest.xml 을작성한다. 예제 22 1 일반적인레이아웃구조앱의 AndroidManifest.xml AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.superdroid.fragmentinclude" android:versioncode="1" android:versionname="1.0" > <uses-sdk android:minsdkversion="16" android:targetsdkversion="16" /> <application android:allowbackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/apptheme" > <activity android:name=".aactivity" android:label="a Activity" > <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> </activity> <activity android:name=".bactivity" android:label="b Activity" /> </application> </manifest> AndroidManifest.xml 에 A, B 액티비티콤포넌트를등록했다. 다음은각액티비티에서사용될레이아웃을구현한다. 예제 22 2 A 액티비티의레이아웃리소스 res/layout/a_activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"> <!-- 부타이틀영역의레이아웃 --> <LinearLayout android:padding="5dp" android:background="#ccc" android:orientation="horizontal"> http://cafe.daum.net/_c21_/bbs_print?grpid=1mwa2&mgrpid=&fldid=pgqt&dataid=4 3/10
<TextView android:layout_width="0dp" android:layout_weight="1" android:text=" 부타이틀영역입니다." /> <Button android:layout_width="wrap_content" android:text=" 메뉴 "/> <Button android:id="@+id/btn_finish" android:layout_width="wrap_content" android:text=" 종료 " android:0nclick="0nclick"/> <!-- A 액티비티 Content 영역의레이아웃 --> <TextView android:layout_height="0dp" android:layout_weight="1" android:gravity="center" android:textsize="25dp" android:text="a Activity Content Layout" /> <Button android:id="@+id/btn_run_b_activity" android:text="run B Activity" android:0nclick="0nclick"/> 예제 22 3 B 액티비티의레이아웃리소스 res/layout/b_activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"> <!-- 부타이틀영역의레이아웃 --> <LinearLayout android:padding="5dp" android:background="#ccc" android:orientation="horizontal"> <TextView android:layout_width="0dp" android:layout_weight="1" android:text=" 부타이틀영역입니다." /> http://cafe.daum.net/_c21_/bbs_print?grpid=1mwa2&mgrpid=&fldid=pgqt&dataid=4 4/10
<Button android:layout_width="wrap_content" android:text=" 메뉴 "/> <Button android:id="@+id/btn_finish" android:layout_width="wrap_content" android:text=" 종료 " android:0nclick="0nclick"/> <!-- B 액티비티 Content 영역의레이아웃 --> <TextView android:gravity="center" android:textsize="25dp" android:text="b Activity Content Layout" /> 다음은 A, B 액티비티소스를구현한다. 예제 22 4 A 액티비티 src/aactivity.java public class AActivity extends Activity @Override protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.a_activity_main); public void 0nClick( View v ) switch( v.getid() ) case R.id.btn_finish: finish(); break; case R.id.btn_run_b_activity: Intent intent = new Intent(this, BActivity.class); startactivity(intent); break; http://cafe.daum.net/_c21_/bbs_print?grpid=1mwa2&mgrpid=&fldid=pgqt&dataid=4 5/10
예제 22 5 B 액티비티 src/bactivity.java public class BActivity extends Activity @Override protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.b_activity_main); public void 0nClick( View v ) switch( v.getid() ) case R.id.btn_finish: finish(); break; 예제를실행하여결과를확인해보자. 그림 22 4 일반적인레이아웃예제앱실행결과 1 A 액티비티가실행되었다. 레이아웃을살펴보면상단에부제목영역과하단에 A 액티비티의콘텐트영역 이존재한다. 2 Run B Activity 버튼을눌러 B 액티비티를실행한다. 3 B 액티비티가실행되었다. 레이아웃을살펴보면상단에부제목영역과하단에 B 액티비티의콘텐트영역 이존재한다. 4 종료버튼을누른다. B 액티비티는종료되고 A 액티비티로복귀된다. 지금까지예제소스에서불편한점한가지를발견했는가! [ 그림 22 4] 를통해살펴보자. 그림 22 5 중복레이아웃영역 http://cafe.daum.net/_c21_/bbs_print?grpid=1mwa2&mgrpid=&fldid=pgqt&dataid=4 6/10
1 A 는 B 액티비티를실행하고있다. 2 여기서 A, B 액티비티의레이아웃을살펴보면상단부제목영역이공통적으로존재한다. 3 만일 C, D, E 등으로더많은액티비티를실행하게된다면중복된부제목영역이계속추가되어야하고, 액티비티의레이아웃리소스에 [ 예제 22 2], [ 예제 22 3] 과같이반복적으로부제목영역의레이아웃코드를추가해줘야할것이다. 또한부제목영역의레이아웃이변경되기라도한다면모든레이아웃리소스들을수정해줘야하기때문에불편하다. 이렇게중복된레이아웃은소스의양을증가시키고유지보수를어렵게한다. 이문제를해결하기위해레이아웃에는 include 요소를제공하고있다. 그렇다면 include 요소를직접사용해보자. 22.1.2 include 요소활용 먼저중복되어사용되는레이아웃영역을별도의레이아웃 XML 파일로분리한다. 예제 22 6 중복레이아웃영역분리 res/layout/subtitle_layout.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:padding="5dp" android:background="#ccc" android:orientation="horizontal"> <TextView android:layout_width="0dp" android:layout_weight="1" android:text=" 부타이틀영역입니다." /> <Button android:layout_width="wrap_content" android:text=" 메뉴 "/> <Button android:id="@+id/btn_finish" android:layout_width="wrap_content" android:text=" 종료 " android:0nclick="0nclick"/> http://cafe.daum.net/_c21_/bbs_print?grpid=1mwa2&mgrpid=&fldid=pgqt&dataid=4 7/10
이제분리된레이아웃을 A, B 액티비티레이아웃리소스에적용해보자. 예제 22 7 A 액티비티레이아웃리소스 res/layout/a_activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"> <!-- 부타이틀영역의레이아웃 --> <include layout="@layout/subtitle_layout"/> <!-- A 액티비티 Content 영역의레이아웃 --> <TextView android:layout_height="0dp" android:layout_weight="1" android:gravity="center" android:textsize="25dp" android:text="a Activity Content Layout" /> <Button android:id="@+id/btn_run_b_activity" android:text="run B Activity" android:0nclick="0nclick"/> 예제 22 8 B 액티비티레이아웃리소스 res/layout/b_activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical"> <!-- 부타이틀영역의레이아웃 --> <include layout="@layout/subtitle_layout"/> <!-- B 액티비티 Content 영역의레이아웃 --> <TextView android:gravity="center" android:textsize="25dp" android:text="b Activity Content Layout" /> 간단히부제목영역의레이아웃을제거하고, 그부분에 include 요소를추가한다음 layout 속성값으로분리된레이 아웃리소스 ID 를적어주면끝이다. http://cafe.daum.net/_c21_/bbs_print?grpid=1mwa2&mgrpid=&fldid=pgqt&dataid=4 8/10
22.1.3 include 요소의한계 공통적으로사용될레이아웃을분리하여필요한레이아웃에끼워넣는 include 요소의장점은딱거기까지다. 즉레이아웃리소스의소스양을줄여유지보수하기쉽도록돕는다는점이외에는특별한것이없다는것이다. 물론이것만으로도충분한가치가있고꼭알고있어야할기술임에는분명하다. 어쨌든 include 요소의한계는무엇이고, 어떤것이더필요한지살펴보자. 그림 22 6 include 요소의한계 1 include 요소를이용하여부제목영역의레이아웃코드는재사용할수있었지만, 레이아웃객체는액티비티마다각각존재해서비효율적이다. 뿐만아니라 [ 예제 22 4], [ 예제 22 5] 와같이액티비티마다부제목영역의버튼처리를자바소스로각각중복해서구현해주어야해서유지보수가어렵다. 물론 A, B 액티비티가특정액티비티를상속받도록구현하고, 그상위액티비티에서부제목영역의처리를담당한다면이문제는해결될수있다. 하지만다음의상황에서또다른문제점이발생된다. 2 B 액티비티에서종료버튼을누르면 finish 함수를호출하고 A 액티비티로복귀한다. 하지만분명사용자는 앱자체가종료된다고생각할것이다. 3 그리고 A 액티비티에서종료버튼을누르면 A 액티비티가종료되고태스크하위에더이상액티비티가존 재하지않기때문에홈으로복귀한다. 즉앱이종료되었다고볼수있다. 결국 A, B 액티비티의부제목영역 의처리는동일한결과를처리할수없다. 이는 A, B 액티비티가분리되었기때문이다. 4 이문제를해결하려면 A, B 액티비티를하나의액티비티로합치면된다. 5 합쳐진액티비티레이아웃에는상단에고정영역의레이아웃이존재하고 6 하단에는콘텐트내용이변하는가변영역의레이아웃이존재하게된다. 7 가변영역은 FrameLayout 영역으로설정하고 A, B 의레이아웃을서로감췄다보여줬다하면서이동하면 된다. 8 여러액티비티에들어갈레이아웃을하나의액티비티에포함하고서로전환하면서보여주는것은매우효 율적이다. 하지만만일두가지레이아웃이아니라 C, D, E 등전환할레이아웃개수가늘어난다면하나 http://cafe.daum.net/_c21_/bbs_print?grpid=1mwa2&mgrpid=&fldid=pgqt&dataid=4 9/10
의액티비티에서처리하기가매우복잡할뿐만아니라관리하기도쉽지않을것이다. [ 그림 22 6] 의 8 과같은문제를해결하기위해바로액티비티그룹 ActivityGroup 이라는것이존재한다. 다음글에서계속됩니다. [ 참고예제소스 ] 22 1. Include 요소적용전일반적인레이아웃.zip 22 2. Include 요소적용.zip http://cafe.daum.net/_c21_/bbs_print?grpid=1mwa2&mgrpid=&fldid=pgqt&dataid=4 10/10