꿈꾸는 시스템 디자이너

프레그먼트(Fragment)간 통신(Communication) 예제 본문

Development/Android

프레그먼트(Fragment)간 통신(Communication) 예제

독행소년 2013. 8. 2. 13:57

한 Activity내에 GUI의 구성이 복잡할 때 이를 모듈화할 때 Fragment가 사용된다. 즉 한 Activity를 구성할 GUI 조각들의 집합이다.

우선 Layout의 구성부터 살펴보자.


<activity_main.xml>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <!-- 상단에 표시될 프레그먼트 -->

    <fragment
        android:id="@+id/head_fragment"
        android:name="com.example.fragmenttest.HeadFragment"
        android:layout_width="match_parent"
        android:layout_height="230dp" />

    <!-- 데코레이션 -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#1e90ff"
        android:orientation="vertical" >
    </LinearLayout>

    <!-- 하단에 표시할 프레그먼 -->

    <fragment
        android:id="@+id/tail_fragment"
        android:name="com.example.fragmenttest.TailFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>


MainActivity 엑티비티를 구성하는 activity_main.xml의 내용으로 두개의 프레그먼트를 가지고 있다. 

  • line 16,17
첫번째 프레그먼트의 id와 name 등을 정의하고 있다. 
- id: 참조를 위한 id이며, 동시에 프레그먼트의 레이아웃 xml 파일명
- name: 프레그먼트를 구현한 패키지 및 클래스명
  • line 32,33
윗 내용을 참고하면, 두번째 프레그먼트는 com.example.fragmenttest 패키지내에 TailFragment.java 파일로 구현될 것이며, 프레그먼트의 레이아웃은 layout폴더 및에 tail_fragment.xml 파일로 정의되고 R.layout.tail_fragment로 참조 가능하다.

<head_fragment.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" >

    <Button
        android:id="@+id/headBt1"
        style="?android:attr/buttonStyleSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button1" />

    <Button
        android:id="@+id/headBt2"
        style="?android:attr/buttonStyleSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button2" />
</LinearLayout>


<tail_fragment.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/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Large Text"
        android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>

정의한 두 프레그먼트의 레이아웃은 위와 같다. 결과적으로 하나의 엑티비티에 두개의 프레그먼트를 상/하로 배치하고 상단 프레그먼트에는 두개의 버튼을 하단의 프레그먼트에는 하나의 텍스트뷰가 표시된다.



결과적으로 개발하고 싶은 내용은 상단 프레그먼트의 버튼을 누르면 하단의 프레그먼트에서 어떤 버튼이 클릭되었는지를 표시하는 아래와 같은 앱이다.



우선 프레그먼트간의 직접적인 데이터 전달은 불가능하다. 중간에 엑티비티를 매개로 해야 한다. 즉 HeadFragment -> MainActivity ->TailFragment 순으로 통신이 이루어져야 한다.


HeadFragment가 MainActivity로 신호를 전달하기 위해서는 프레그먼트에 인터페이스를 정의하고, 이를 엑티비에서 구현함으로써 가능하게 한다.

<HeadFragment.java>

package com.example.fragmenttest;

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;

public class HeadFragment extends Fragment{

	private Button headBt1,headBt2;
	private boolean isDone = false;

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		return inflater.inflate(R.layout.head_fragment, container, false);
	}

	@Override
	public void onResume() {
		if(!isDone){
		headBt1 = (Button)this.getActivity().findViewById(R.id.headBt1);
		headBt2 = (Button)this.getActivity().findViewById(R.id.headBt2);
		// 버튼에 OnClickListener를 설정
		headBt1.setOnClickListener(onClickListener);
		headBt2.setOnClickListener(onClickListener);
		isDone = true;
		}
		super.onResume();
	}
	
	// Activity 로 데이터를 전달할 커스텀 리스너
	private CustomOnClickListener customListener;
	
	// Activity 로 데이터를 전달할 커스텀 리스너의 인터페이스
	public interface CustomOnClickListener{
		public void onClicked(int id);
	}
	
	// 버튼에 설정한 OnClickListener의 구현, 버튼이 클릭 될 때마다 Activity의 커스텀 리스너를 호출함
	OnClickListener onClickListener = new OnClickListener(){

		@Override
		public void onClick(View v) {
			customListener.onClicked(v.getId());
		}
	};

	// Activity 로 데이터를 전달할 커스텀 리스너를 연결
	@Override
	public void onAttach(Activity activity) {
		super.onAttach(activity);
		customListener = (CustomOnClickListener)activity;
	}
}

위 코드 내용을 보면 버튼이 클릭될 때마다 custoListner의 onClicked()가 호출됨을 알 수 있다. customListener는 CustomOnClickListener의 객체이고  CustomOnClickListner는 본 프레그먼트에서 정의한 인터페이스이다. 즉 50번째 줄의 onClicked()은 본 프레그먼트에서 개발자가 임의로 선언한 인터페이스내에 존재하는 메소드이다. 이 인터페이스를 메인엑티비티에서 구현함으로써 프레그먼트가 메인엑티비티로 신호를 전달 할 수 있게 된다.

그리고 또한가지 중요한 것은 메인엑티비티로 신호를 전달할 customListener를 onAttach()에서 연결해 주어야 한다는 것이다(line 56~58).


<MainActivity.java>

package com.example.fragmenttest;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity implements HeadFragment.CustomOnClickListener{
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}

	// HeadFragment.CustomOnClickListener의 구현
	@Override
	public void onClicked(int id) {
		TailFragment tailFragment = (TailFragment)getFragmentManager().findFragmentById(R.id.tail_fragment);
		switch(id){
		case R.id.headBt1:
			tailFragment.setText("Button1 is Clicked");
			break;
		case R.id.headBt2:
			tailFragment.setText("Button2 is Clicked");
			break;
		}
	}
}

위 코드 내용을 살펴보면, 6번 째 줄에서 HeadFragment.CustomOnClickListener를 구현함을 정이하고 있고, 16번 째 줄에서 이를 실제로 구현하고 있다. HeadFragment의 버튼들이 클릭되면 MainActivity의 onClicked()가 호출되고 TailFragment의 setText()를 호출함으로써 텍스트뷰의 내용을 변경하게 된다(line 20,23).


<TailFragment.java>

package com.example.fragmenttest;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class TailFragment extends Fragment{

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		return inflater.inflate(R.layout.tail_fragment, container, false);
	}
	
	public void setText(String text){
		TextView tv = (TextView)getView().findViewById(R.id.textView);
		tv.setText(text);
	}
}

18번 째 줄에서 정의한 setText()메소드를 이용하여 텍스트뷰의 내용을 변경한다.


이로써, HeadFragment의 버튼이 클릭되면 인터페이스를 통해 MainActivity의 onClicked()메소드가 호출되고, onClicked()에서 TailFragment의 setText()메소드가 호출되어 텍스트뷰의 내용이 변경되는 과정을 살펴보았다.

'Development > Android' 카테고리의 다른 글

AppWidget에서의 View 제어  (0) 2013.08.27
View 롤오버 처리(텍스트 색상, 배경 색상)  (0) 2013.08.07
SQLiteOpenHelper 사용법  (1) 2013.07.25
간단한 SQLite 예제  (0) 2013.07.19
ProgressDialog와 AlertDialog 사용법  (0) 2013.07.15
Comments