반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리

Sencha Touch 1.x 관련 메모

2013. 10. 1. 11:35 | Posted by 솔웅


반응형

* 앱 시작하기


Ext.setup({
    tabletStartupScreen: 'tablet_startup.png',
    phoneStartupScreen: 'phone_startup.png',
    icon: 'icon.png',
    glossOnIcon: false,
    statusBarStyle: 'default',
 
onReady: function(){
new Ext.Panel(
{
    fullscreen: true,
    html: 'Hello Sencha Touch'
}
);
}
});



new Ext.Application({
launch: function() {
new Ext.Panel(
{
fullscreen: true,
html: ‘Hello Sencha Touch’
}
);
}
});


MVC - Ext.Application




* Theme : Sass (Ruby) - CSS를 프로그래밍하듯이 작성할 수 있음
  Sass 내장함수 : http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html
  > sass filename.scss filename.css
  > css2sass filename.css filename.scss
  > sass -style compressed filename.scss filename.css



* Compass : Sass 를 좀 더 편리하게 개발할 수 있도록 함 http://compass-style.org/



* 설치
  - Ruby 설치 http://www.ruby-lang.org/ko/downloads/
  - Sass & Compass 설치
    > gem install haml
    > gem install compass


* config.rb : 컴파일 옵션



* resources/themes/stylesheets/sencha-touch/default/_variables.scss
  $base-color : 앱의 기본 색상 정의
  $base-gradient : ‘matte’, ‘glossy’, ‘flat’, ‘bevel’, ‘recessed’ etc.
  > compass compile sencha-touch.scss
  > compass -watch



* Ext.Panel



Ext.setup({
onReady: function(){
new Ext.Panel({          Panel 객체 생성, <dev>요소로 DOM에 추가 됨
fullscreen: true,        전체 화면
style: "...",          CSS 지정
layout: { ... },         레이아웃 정보
items: [ { ... }, { ... }, ... ],         UI 아이템들 지정
dockedItems: [ { ... }, { ... }, ... ]         도킹 아이템 지정. Panel의 상하좌우에 밀착된 아이템
});
}
});



* dockedItems


dockedItems: [
{
dock: "top",
style: "background-color:red;",
html: "DockItem-Top"
},
{
dock: "left",
style: "background-color:gray;",
html: "DockItem-Left"
},
{
dock: "bottom",
style: "background-color:yellow;",
html: "DockItem-Bottom"
},
{
dock: "right",
style: "background-color:green;",
html: "DockItem-Right"
}
}



* layout


layout: {
type: 'vbox',
align: 'stretch',
pack: 'center'
},



* items : 객체 생성


items:[
new Ext.Button({ text: ‘button1’ })
]



* Ext.TabPanel


Ext.setup({
onReady: function(){
var item1 = {
title: 'Tab1',
style: "background-color: red;",
html: 'Item1'
};
var item2 = {
title: 'Tab2',
style: "background-color: gray;",
html: 'Item2'
};
var item3 = {
title: 'Tab3',
style: "background-color: yellow;",
html: 'Item3'
};
var panel = new Ext.TabPanel({
fullscreen: true,
ui: 'dark',
tabBarDock: 'top',
cardSwitchAnimation: 'slide',
items: [item1,item2,item3]
});
}
});



* Ext.Carousel


Ext.setup({
onReady: function(){
var item1 = {
style: "background-color:red;",
html: 'Item1'
};
var item2 = {
style: "background-color:gray;",
html: 'Item2'
};
var item3 = {
style: "background-color:yellow;",
html: 'Item3'
};
var panel = new Ext.Carousel({
fullscreen: true,
ui: 'dark',
indicator: true,
direction: 'horizontal',
items: [item1,item2,item3]
});
}
});


* Multi Carousel


Ext.setup({
onReady: function(){
var item1 = {
style: "background-color:red;",
html: 'Item1'
};
var item2 = {
style: "background-color:gray;",
html: 'Item2'
};
var item3 = {
style: "background-color:yellow;",
html: 'Item3'
};
var topCarousel = new Ext.Carousel({
items: [item1,item2,item3]
});
var middleCarousel = new Ext.Carousel({
items: [item1,item2,item3]
});
var bottomCarousel = new Ext.Carousel({
items: [item1,item2,item3]
});
var panel = new Ext.Panel({
fullscreen: true,
layout:{
type: 'vbox',
align: 'stretch'
},
defaults: {flex: 1},
items: [topCarousel, middleCarousel, bottomCarousel]
});
}
});



* Ext.Toolbar


Ext.setup({
onReady: function(){
var panel = new Ext.Panel({
fullscreen: true,
dockedItems: [{
xtype: 'toolbar',
dock: 'top',
title: 'My Toolbar',
defaults: {
xtype: 'button'
},
items: [
{ ui: 'decline-round', text:'decline-round' }
]
}]
});
}
});



* Ext.Button


Ext.setup({
onReady: function(){
new Ext.Panel({
fullscreen: true,
layout: {
type: 'vbox',
align: 'start'
},
defaults: {
layout: { type: 'hbox' },
flex:1,
defaults: {
xtype: 'button'
}
},
items:[
{items: [
{ ui: 'normal', text:'Normal',
handler: function() {
Ext.Msg.alert('Message', 'Hi~~', Ext.emptyFn);
}
},
{ui: 'round', text:'Round'},
{ui: 'small', text:'Small'}
]},
{items: [
{ui: 'decline', text:'Drastic'},
{ui: 'decline-round', text:'Round'},
{ui: 'decline-small', text:'Small'}
]},
{items: [
{ui: 'confirm', text:'Confirm'},
{ui: 'confirm-round', text:'Round'},
{ui: 'confirm-small', text:'Small'}
]},
{items: [
{ui: 'action', text:'Action'},
{ui: 'action-round', text:'Round'},
{ui: 'action-small', text:'Small'}
]},
{items: [
{ui: 'back', text:'back'},
{ui: 'Forward', text:'Forward'}
]}
]
});
}
});



* SegmentedButton


Ext.setup({
onReady: function(){
var segmentedButton = [{
xtype: 'segmentedbutton',
allowMultiple: false,
allowDepress: false,
items: [
{ text: 'Toggle 1' },
{ text: 'Toggle 2', pressed : true },
{ text: 'Toggle 3' }
],
listeners : {
toggle : function(container, button, active){
Ext.Msg.alert('Tap', button.text + " : " + (active ? 'on' : 'off'), Ext.emptyFn);
}
}
}];
new Ext.Panel({
fullscreen: true,
dockedItems:{
xtype: 'toolbar',
ui: 'light',
items: [segmentedButton]
}
});
}
});



* iconCls


Ext.setup({
onReady: function(){
var item1 = { title: 'info', iconCls: 'info', badgeText:'2',};
var item2 = { title: 'favorites', iconCls: 'favorites' };
var item3 = { title: 'settings', iconCls: 'settings' };
var item4 = { title: 'bookmarks', iconCls: 'bookmarks' };
var item5 = { title: 'download', iconCls: 'download' };
var item6 = { title: 'more', iconCls: 'more' };
var item7 = { title: 'search', iconCls: 'search' };
var item8 = { title: 'team', iconCls: 'team' };
var item9 = { title: 'time', iconCls: 'time' };
var item10 = { title: 'user', iconCls: 'user' };
var item11 = { title: 'action', iconCls: 'action' };
var item12 = { title: 'add', iconCls: 'add' };
var item13 = { title: 'arrow_up', iconCls: 'arrow_up' };
var item14 = { title: 'arrow_right', iconCls: 'arrow_right' };
var item15 = { title: 'arrow_down', iconCls: 'arrow_down' };
var item16 = { title: 'arrow_left', iconCls: 'arrow_left' };
var item17 = { title: 'compose', iconCls: 'compose' };
var item18 = { title: 'delete', iconCls: 'delete' };
var item19 = { title: 'refresh', iconCls: 'refresh' };
var item20 = { title: 'reply', iconCls: 'reply' };
var item21 = { title: 'star', iconCls: 'star' };
var item22 = { title: 'trash', iconCls: 'trash' };
var panel = new Ext.TabPanel({
fullscreen: true,
ui: 'light',
cardSwitchAnimation: 'slide',
tabBar: {
dock: 'bottom',
scroll: 'horizontal'
},
items:
[
item1,item2,item3,item4,item5,item6,item7,item8,item9,item10,
item11,item12,item13,item14,item15,item16,item17,item18,item19,item20,
item21,item22
]
});
}
});



* Overlay : HTML과 스크립트 모두 작업해야 함

* Ext.List

* Ext.MessageBox : Alert, Confirm, Prompt


* Ext.is
  width: Ext.is.Phone ? 260 : 400,
  height: Ext.is.Phone ? 220 : 400


* contentEl : html을 사용해서 레이아웃 구성



********************** 이상 UI 와 관련해서 ************************

* Ajax

* Ext.Template : HTML 태그 모형


var myTpl = new Ext.Template([
'<div>',
'<span> <b>{name}</b> is {value} </span>',
'</div>'
]);
Ext.setup({
onReady: function(){
var panel = new Ext.Panel({
fullscreen:true,
tpl: myTpl
});
panel.update(
{
name: "Sencha Touch",
value: "The First HTML5 Mobile Web App Framework"
}
);
}
});



* Ext.XTemplate : 배열 형태의 데이터를 쉽게 다룰 수 있음



* Ajax 호출 : Ext.Ajax
    • url: Ajax 통신 대상이 되는 원격지의 URL
    • timeout: 네트워크 통신이 항상 안정적이지는 않다. 따라서 적절한 타임아웃 설정이 필요하다. Ajax 통신 과정에서 타임아웃 시간을 초과하면 더는 기다리지 않고 실패로 처리하는 것이 좋다. 이 속성에 타임아웃 값을 밀리초 단위로 지정한다. 기본값은 30,000밀리초(약 30초)다.
    • success 함수: Ajax 통신이 성공하면 실행되는 함수
    • failure 함수: Ajax 통신이 실패하면 실행되는 함수
    • callback 함수: 성공/실패와 상관없이 Ajax 통신이 완료되면 실행되는 함수



* JSONP : 크로스도메인 접근을 가능하도록 함
 <script type=’text/javascript’ src=’http://anotherDomain/server.js’></script>



Ext.util.JSONP.callback(
{
"name": "Sencha Touch",
"value": "The First HTML5 Mobile Web App Framework"
}
)



Ext.util.JSONP.request({ .......



**************************************



* Data package



* Ext.data.Proxy
  - ServerProxy : 원격지 서버에서 데이터 로딩
  - ClientProxy : 로컬 저장소로부터 데이터 로딩



* Ext.data.Reader : proxy로 얻어온 데이터 해석하고 데이터 모델 객체로 생성함
  - JsonReader
  - XmlReader

 

* Ext.data.Store : 데이터의 연산을 수행할 수 있도록 함
  - inline Data


var store = new Ext.data.Store({
data: [
{firstName: 'Julio', lastName: 'Benesh'},
{firstName: 'Julio', lastName: 'Minich'},
{firstName: 'Tania', lastName: 'Ricco'},
………
]


  - External Data


var store = new Ext.data.Store({
proxy: {
type: 'ajax',
url : 'server.html',
reader: {
type: 'json',
root: 'users'
}
}
});



* DataView : Store에 저장된 데이터를 UI에 표현하기 위한 컴포넌트 객체 (Ext.List가 이 클래스를 상속함)



* Ext.Template : 데이터의 레이아웃을 결정할 때 사용 (XTemplate)



* 원격지 서버의 리소스 호출 : Mode, Store, Proxy, Reader 이용
  - JsonReader 사용
  - XmlReader 사용



* 데이터 정렬과 필터링
  - Store 객체의 sort()와 filter() 함수


jsonStore.sort(‘firstName’,’DESC’); //firstName을 기준으로 내림차순 정렬
jsonStore.filter(‘firstName’, ‘JM’);. //firstName 값이 ‘JM’인 것만 조회



* Ext.data.ClientProxy 클래스를 상속받은 객체를 통해 로컬 자원에 액세스할 수 있음
  - Memory
  - Web Storage : HTML5에서 추가된 클라이언트 측 저장소
    : LocalStorage (영구저장소)
    : SessionStorage (임시저장소)
  - ClientProxy, WebStorageProxy 상속받아 LocalStorageProxy 객체나 SessionStorageProxy 객체 이용



* Ext.NestedList : 리스트를 계층 구조로 표현할 수 있음 : 타이틀바의 제목이나 뒤로가기 버튼이 자동으로 생성 됨



***********************************


* Event
  - handler 를 이용한 버튼 탭 이벤트 처리


new Ext.Button({
text: 'MyButton',
handler: function(btn, event){
Ext.Msg.alert('Title', btn.text, Ext.emptyFn);
}
})
 

  - onItemDisclosure 속성을 이용한 리스트 탭 이벤트 처리



new Ext.List({
itemTpl : '{firstName} {lastName}',
store: store,
onItemDisclosure: function(record, btn, index) {
Ext.Msg.alert('Message', record.get('firstName'), Ext.emptyFn);
}
}


* 표준 이벤트 처리
  - listeners를 이용한 인라인 이벤트 처리


new Ext.Button({
text: 'MyButton',
listeners: {
tap: function(btn, event){ console.log(event.type); },
click: {
element: 'el',
fn: function(event){ console.log(event.type); }
}
}
})



  - 0n() 함수를 이용한 이벤트 처리


btn.on({
'tap' : {
fn: function(event){ console.log('tap')},
delay: 2000
},
'click' : {
element: 'el',
fn: function(event){ console.log('click')},
}
});



* 리스트의 itemtap, itemswipe 이벤트



* Touch Event
  - 탭(Tap) 관련 이벤트 : tap, singletap , doubletap, taphold, tapcancel
  - 터치(Touch) 관련 이벤트 : touchstart, touchend, touchmove, touchdown
  - 스윕(Swipe) 이벤트 : swipe
  - 핀치(Pinch) 관련 이벤트 : pinch, pinchstart, pinchend
  - 드래그(Drag) 및 스크롤(Scroll) 관련 이벤트 : drag, dragstart, dragend, scroll, scrollstart, scrollend



*****************************



* Media 지원 : HTML5에 추가된 Video, Audio 사용. Ext.Video, Ext.Audio



* Ext.Media
  - autoPause  : 미디어가 비활성화(deactivate)될 때 자동으로 일시정지할지 결정한다(기본값: true).
  - autoResume : 미디어가 활성화(activate)될 때 자동으로 재생할지 결정한다(기본값: false)
  - enableControls : 미디어 재생을 제어하는 컨트롤 바의 표시 여부를 결정한다(기본값: true).
  - url : 미디어 소스를 지정한다
  - play() : 미디어를 재생한다.
  - pause() : 미디어 재생을 일지정지한다.
  - toggle() : 미디어 재생과 일시정지를 번갈아 처리하는 토글 기능을 제공한다.



* Ext.Video


Ext.setup({
onReady: function() {
var pnl = new Ext.Panel({
fullscreen: true,
layout: {
type: 'vbox',
pack: 'center'
},
items: [{
xtype: 'video',
url: 'space.mp4',
loop: true,
width: 500,
height: 400,
posterUrl: 'Screenshot.png'
}]
})
}
});



* Ext.Audio


Ext.setup({
onReady: function() {
var pnl = new Ext.Panel({
fullscreen: true,
layout: {
type: 'vbox',
pack: 'center'
},
items: [{
xtype: 'audio',
url: 'crash.mp3',
loop: true
}]
})
}
});



반응형

[CookBook] Fragments 이해하기 -8-

2013. 9. 30. 22:43 | Posted by 솔웅


반응형

Displaying Options Using ListFragment



ListFragment는 이미 만들어진 리스트뷰를 가지고 있는 fragment 입니다. 리스트 뷰에 들어갈 내용들(data source)는 array나 cursor가 될 수 있습니다. 이 ListFragments를 이해하기 위해서 리스트뷰와 텍스트뷰를 포함하고 있는 어플리케이션을 만들어 보겠습니다. 리스트 뷰에는 아이템들이 들어갈 것이고 이 아이템을 선택하면 텍스트 뷰에 표시되도록 만들 겁니다. 이 앱에서 리스트뷰는 ListFragment를 통해서 표시됩니다. 이 새로운 프로젝트의 이름은 ListFragmentApp으로 하겠습니다. 우선 텍스트뷰를 표시할 fragment부터 만들겠습니다. fragment2.xml 이라는 layout xml을 res/layout 폴더에 만들겠습니다.


fragment2.xml



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <TextView 
        android:id="@+id/selectedopt"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Please select a product"
       android:textSize="@dimen/text_size"
       android:textStyle="bold"  />
 </LinearLayout>




id가 selectedopt라는 텍스트뷰가 LinearLayout 안에 정의돼 있습니다. 일단 Please select a product라는 문자가 세팅돼 있습니다. 이 텍스트는 볼드체이고 size는 dimension resource에서 지정된 text_size를 사용합니다. 이 텍스트 뷰는 자바 코드에서 리스트뷰에서 선택된 아이템의 값을 표시하도록 만들어질 겁니다.



device의 화면크기에 맞게 리스트뷰의 아이템들이 표시되도록 하기 위해서 list_item.xml 파일을 res/layout 폴더 밑에 만들어 넣겠습니다.



list_item.xml



<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="6dp"
      android:textSize="@dimen/text_size"
      android:textStyle="bold" />
     


보시면 리스트뷰에 있는 아이템들은 6dp 의 패딩을 갖게 돼 있습니다. 그리고 텍스트는 bold 체이고 크기는 dimension resource에 있는 text_size를 갖다가 사용합니다.


fragment2.xml로 부터 fragment의 UI를 load 하기 위해 자바 클래스를 만들겠습니다.



Fragment2Activity.java

    


public class Fragment2Activity extends Fragment {
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment2, container, false);
    }

    public void dispOption(String msg){
        TextView selectedOpt = (TextView) getActivity().findViewById(R.id.selectedopt);
        selectedOpt.setText("You have selected "+msg);  
    }
}

 


이 클래스는 Fragment base 클래스를 extends 했습니다. onCreateView() 메소드를 오버라이드 해 fragment2.xml에서 정의한 텍스트 뷰 UI를 inflate 하기 위해 LayoutInflater를 그 안에서 사용했습니다.

 

이제 리스트뷰를 만들기 위해서 ListFragment를 사용할 겁니다. 이 ListFragment는 리스트뷰를 갖고 있습니다. 그러니까 이 fragment를 위해서 따로 UI를 정의할 필요는 없습니다. ListFragment 클래스를 extends한 자바클래스에서 동적으로 추가하시면 됩니다. 이 자바 클래스 안에서 리스트뷰에 들어갈 아이템들을 동적으로 할당할 겁니다. 그리고 리스트뷰에서 선택된 아이템을 Fragment2의 텍스트 뷰로 전달해서 화면에 표시하도록 할 거구요.
 
 

Fragment1Activity.java
 
 

public class Fragment1Activity extends ListFragment {
    String[] products={"Camera", "Laptop", "Watch",  "Smartphone", "Television"};

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ArrayAdapter<String> arrayAdpt = new ArrayAdapter  <String>(getActivity(),R.layout.list_item, products);
        setListAdapter(arrayAdpt);
    }

    @Override
    public void onListItemClick(ListView l, View v, int  position, long id) {
        Fragment2Activity frag = (Fragment2Activity) getFragmentManager().findFragmentById(R.id.fragment2);
        frag.dispOption(((TextView) v).getText().toString());                         
    }
}



보시다 시피 ListFragment를 extends 했습니다. 리스트뷰를 사용할 거기 때문이죠. 이 리스트뷰에 아이템을 표시하기 위해서 아이템들이 들어있는 products라는 배열을 만들었습니다. 그리고 onCreate() 메소드를 보시죠. 여기서는 ArrayAdapter를 만들어서 list_item.xml 을 할당해 주고 위에서 만든 products 배열도 할당해 줬습니다. 그리고 setListAdapter()메소드를 사용해서 이 ArrayAdapter를 세팅했구요. 이러면 이 ListView에 이 값들이 세팅이 되서 화면에 아이템으로 뿌려질 수 있습니다.



그리고 onListItemClick() 리스너를 사용했죠. 해당 아이템일 클릭되면 실행될 콜백 메소드 입니다. 여기서는 Fragment2Activity 클래스를 초기화한 frag라는 객체를 만들어서 이 frag의 disOption()이라는 메소드를 호출하도록 코딩을 했습니다 코딩할 때 텍스트뷰의 텍스트를 전달하고 있구요.



이제 이 두개의 fragment들을 함께 화면에 표시하도록 해야 합니다.
우선 layout xml을 만듭니다.


activity_list_fragment_app.xml



<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >
    <fragment
        android:name="com.androidtablet.listfragmentapp.Fragment1Activity"
        android:id="@+id/fragment1"
        android:layout_weight="1"
        android:layout_width="wrap_content"
        android:layout_height="match_parent" />
    <fragment
        android:name="com.androidtablet.listfragmentapp.Fragment2Activity"
        android:id="@+id/fragment2"
        android:layout_weight="0"
        android:layout_width="wrap_content"
        android:layout_height="match_parent" />
</LinearLayout>


여기에는 저 위에 만들었던 두개의 fragment가 들어있습니다. 이 두 fragment들을 추가하기 위해 <fragment> element를 사용했죠. android:name 이라는 속성에는 각각 fragment의 클래스 이름이 들어가 있습니다.
이제 이 layout xml을 load 할 자바 클래스를 만들겠습니다. 이 자바 클래스에는 특별히 코딩을 할 필요는 없습니다.



ListFragmentAppActivity.java



public class ListFragmentAppActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list_fragment_app);
    }
}



이렇게 하면 예제가 완성됐습니다.

반응형

[CookBook] Fragments 이해하기 -7-

2013. 9. 30. 08:47 | Posted by 솔웅


반응형

Implementing Communication Between Fragments



fragment들 사이에서 데이터를 전달할 수 있도록 하기 위해 Fragment 클래스에서는 두개의 메소드를 제공하고 있습니다. 바로 setArguments() 와 getArguments() 인데요. setArguments() 메소드는 fragment의 Bundle을 저장합니다. getArguments() 메소드는 이 전달된 정보를 얻기 위해 Bundle을 retrieve 하죠.



아래 코드는 fragment1에서 fragment2로 정보를 전달합니다. frag2_container는 layout xml 에서 지정한 fragment container의 ID 입니다.



#1 Fragment2Activity fragment2 = new Fragment2Activity();
#2 Bundle args = new Bundle();
#3 String message = "Message from Fragment1";
#4    if(null==fragmentManager.findFragmentByTag(TAG2)){
#5        Fragment2Activity fragment2 = new Fragment2Activity();
#6      args.putString("msg", message);
#7      fragment2.setArguments(args);
#8      fragmentTransaction.replace(R.id.frag2_container,fragment2);
#9        String tag = null;
#10        fragmentTransaction.addToBackStack(tag);
#11        fragmentTransaction.commit();
#12 }



#1에 있는 Fragment2Activity는 fragment2의 자바 클래스를 말합니다. fragment2라는 자바 클래스 인스턴스를 생성했습니다.
#2에서는 args라고 하는 Bundle 객체를 생성했습니다.
#3에서는 message라고 하는 String 객체를 생성했죠. 이 메세지는 fragment2에 전달 될 겁니다.
#4번에서는 TAG2라는 fragment가 있는지 여부를 체크합니다. TAG2는 fragment2를 말하는 거니까 fragment2가 있는지 여부를 체크하는 겁니다.
#5번은 Fragment2Activity 자바클래스의 인스턴스를 만들고 #6번에서는 args 번들에 3번에서 정의했던 메세지를 세팅합니다.
#7에서는 fragment2에 이 Bundle 을 세팅하구요.
#8번과 #9번에서는 이전의 fragment를 navigating하는 부분이구요.



이 activity stack은 이전의 activity들을 계속 track 합니다. Back 버튼을 누르면 activity stack에 있는 activity가 pop up 되서 그 activity 가 화면에 보여지게 됩니다. 다른 말로 이 activity stack은 Back 버튼을 누르면 이전 화면으로 돌아갈 수 있도록 만드는 거죠.



fragment도 이러한 개념을 사용합니다. back stack에 FragmentTransaction을 추가하려면 commit() 하기 전에 FragmentTransaction의 addToBackStack() 메소드를 호출해야 합니다.



위 코드에서 보면 처음에는 xml에 있는 fragment가 화면에 보였다가 두번째 fragment로 replace됐습니다. 그리고 이전 fragment는 BackStack에 넣구요. 그래서 Back 버튼을 누르면 이전의 FragmentTransaction이 돌아와서 이전의 fragment가 화면에 보여질 겁니다.



Bundle을 통해서 위에 setArguments()메세지를 통해 세팅된 정보를 어떻게 다음 fragment에서 이 메세지를 받고 display하는지에 대해서도 궁금할 겁니다. 그 답은 Bundle을 사용해서 fragment에서 메세지를 받는 것은 getArgument() 메소드를 사용한다 입니다.
아래에 샘플 코드가 있습니다.



String messageReceived = "";
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    ViewGroup container, Bundle savedInstanceState) {
        Bundle bundle = getArguments();
        if(bundle != null) {
            messageReceived = bundle.getString("msg");
        }
    }
}


fragment끼리의 communication을 이해하기 위해 FragmentsByCodeApp 어플리케이션에서 fragment1에서 fragment 2로 메세지를 보내는 것을 구현하겠습니다. 이를 위해 FragmentsByCodeAppActivity.java 의 코드를 수정합니다.



public class FragmentsByCodeAppActivity extends Activity implements OnOptionSelectedListener {
    private static final String TAG1 = "1";
    private static final String TAG2 = "2";
   
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fragments_by_code_app);
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        if(null==fragmentManager.findFragmentByTag(TAG1)){
            Fragment1Activity fragment1 = new Fragment1Activity();
            fragmentTransaction.add(R.id.frag1_container, fragment1, TAG1); 
        }
        Bundle args = new Bundle();
        String message="Message from Fragment 1";  

        if(null==fragmentManager.findFragmentByTag(TAG2)){
            Fragment2Activity fragment2 = new Fragment2Activity();
            args.putString("msg", message);
            fragment2.setArguments(args);

            fragmentTransaction.add(R.id.frag2_container, fragment2, TAG2); 
        }
        fragmentTransaction.commit();
        }

    public void onOptionSelected(String msg){
        Fragment2Activity frag2 = (Fragment2Activity) getFragmentManager().findFragmentById(R.id.frag2_container);
        frag2.dispOption(msg);             
    }
}



우선 Bundle 인스턴스인 args를 생성했습니다. 이 args 객체에 message라는 String 객체를 put 했구요. 그리고 이 Bundle을 fragment2에 넣었습니다. 그 다음에 fragment2에서는 이 Bundle 을 getArguments() 메소드를 이용해서 이 정보를 받습니다. 그 받는 부분을 한번 보겠습니다.



public class Fragment2Activity extends Fragment {
    TextView selectedOpt;
    String messageReceived="";


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View vw= inflater.inflate(R.layout.fragment2,  container, false);
           Bundle bundle=getArguments(); 
           if(bundle !=null) {
               messageReceived = bundle.getString("msg");
               selectedOpt = (TextView) vw.findViewById(R.id.selectedopt);
               selectedOpt.setText(messageReceived);
           }
           return vw;     

    }

    public void dispOption(String msg){
        TextView selectedOpt = (TextView) getActivity().findViewById(R.id.selectedopt);
        selectedOpt.setText("You have selected "+msg);  
    }
}


이렇게 getArguments()를 사용해서 해당 정보를 받습니다. 이렇게 받은 정보는 TextView에 뿌려질 거구요.



이 어플리케이션을 실행하면 아래와 같은 화면을 볼 수 있습니다.






Fragment base 클래스 이외에도 fragment는 다른 몇개의 Fragment 클래스의 subclass들을 extend 할 수 있습니다. DialogFragment, ListFragment, PreferenceFragment들이 그것입니다.

반응형