본문 바로가기

어플리케이션 구성/인텐트(Intent)

인텐트(Intent) 입문- (2) 액티비티간 데이터 주고받기

인텐트를 다루는 두 번째 시간이 돌아왔습니다.  (와우!)
이번 강좌는 저도 인텐트를 쪼~까 공부하느라 뭔가 깔끔하지 못할 지도 모르겠네요(...)
그래도 최대한 자세하게 다뤄보도록 할테니! 걱정은 마시고!! 따라오시면 될겁니다. (아마도요...펑...)

지난 시간에는 다른 액티비티를 단순히 "호출"하는 것만 배웠습니다. 그런데, 실제 어플리케이션을 개발하다보면 액티비티를 호출하는 것은 어찌보면 당연한 것이고, 액티비티간에 데이터를 주고받아야 할 일이 생깁니다. 그럴 땐 어떻게 해야 할까요? => 바로, 이 때도 인텐트를 사용하면 됩니다(...)

인텐트는, 액티비티를 호출하는 수단 뿐 아니라 인텐트 자체에 액티비티간 주고받아야 할 정보들을 실어줄 수 있습니다. 예를 들자면 심부름꾼(???) 이라고 할까나요??

A라는 사람이 B에게 물건을 가져오라고 심부름꾼에게 시키면, 심부름꾼은 B에게 가서 물건을 받아 A에게 전달해주게 됩니다. 마찬가지로, 액티비티 A가 B로부터 어떠한 정보를 받고 싶다면, 인텐트를 사용하여 B를 호출한 다음, 인텐트에 원하는 정보를 실어서 그 정보를 다시 돌려받으면 됩니다.

일단, 호출하는 액티비티 (InformationInput)호출당하는 액티비티(InformationProc)의 코드를 보도록 하겠습니다.


(주의)
액티비티를 추가하는 방법을 모르신다면, 2009/03/01 - [안드로이드/안드로이드 입문] - [강좌] [수정] 이클립스에서 안드로이드 액티비티 추가하기 를 읽고 액티비티 추가 방법에 대해 숙지하신 후 이 강좌를 읽어주세요.


[InformationInput.java]

package com.androidhuman.IntentTest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class InformationInput extends Activity {	
	/** Called when the activity is first created. */
	@Override    public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		final Button requestInfo  = (Button)findViewById(R.id.requestInfo);
		requestInfo.setOnClickListener(new Button.OnClickListener(){ // 버튼을 클릭할 경우
			public void onClick(View v){
				Intent intent = new Intent(InformationInput.this,InformationProc.class);
				startActivityForResult(intent, 1); // Sub_Activity 호출
				}
			});
		}
	
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data){
		super.onActivityResult(requestCode, resultCode, data);
		TextView name_view = (TextView)findViewById(R.id.name_view);
		TextView digit_view = (TextView)findViewById(R.id.digit_view);
		if(resultCode==RESULT_OK) // 액티비티가 정상적으로 종료되었을 경우
			{
			if(requestCode==1) // InformationInput에서 호출한 경우에만 처리합니다.
				{				// 받아온 이름과 전화번호를 InformationInput 액티비티에 표시합니다.
				name_view.setText(data.getStringExtra("data_name"));
				digit_view.setText(data.getStringExtra("data_digit"));
				}
			}
		}
	}


[main.xml]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_height="fill_parent" 
android:layout_width="fill_parent" 
android:orientation="vertical" 
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView android:layout_height="wrap_content" 
android:layout_width="fill_parent" 
android:text="@string/name" />
<TextView android:layout_height="wrap_content" 
   android:layout_width="fill_parent" 
   android:text="-이름이 입력되지 않음-" 
   android:id="@+id/name_view"/>

<TextView android:layout_height="wrap_content" 
    android:layout_width="fill_parent" 
    android:text="@string/digit"/>

<TextView android:layout_height="wrap_content" 
   android:layout_width="fill_parent" 
    android:text="-전화번호가 입력되지 않음-" 
    android:id="@+id/digit_view"/>

<Button android:layout_height="wrap_content" 
    android:layout_width="wrap_content" 
    android:text="@string/button_launch" 
    android:id="@+id/requestInfo"  
    android:layout_gravity="center_horizontal"/>
</LinearLayout>



[InformationProc.java]

package com.androidhuman.IntentTest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class InformationProc extends Activity {	
	/** Called when the activity is first created. */	
	@Override	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.informationproc);
		Button input_info = (Button)findViewById(R.id.inputinfo);
		input_info.setOnClickListener(new OnClickListener(){
			
		public void onClick(View v) { //버튼을 클릭하면
			Intent intent = getIntent(); // 이 액티비티를 시작하게 한 인텐트를 호출
			EditText name_input = (EditText)findViewById(R.id.name_input);
			EditText digit_input = (EditText)findViewById(R.id.digit_input);
			intent.putExtra("data_name",name_input.getText().toString());
			intent.putExtra("data_digit", digit_input.getText().toString());
			setResult(RESULT_OK,intent); // 추가 정보를 넣은 후 다시 인텐트를 반환합니다.
			finish(); // 액티비티 종료
			}
		});
	}



[informationproc.xml]



 


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

<TextView android:layout_height="wrap_content" 
    android:layout_width="wrap_content" 
    android:text="@string/text_information"/>

<LinearLayout android:layout_height="wrap_content" 
    android:layout_width="fill_parent" 
    android:orientation="horizontal" 
    android:id="@+id/name_layout">

<TextView android:layout_height="wrap_content" 
    android:layout_width="wrap_content" 
    android:text="@string/name"/>

<EditText android:layout_height="wrap_content" 
    android:layout_width="fill_parent" 
    android:id="@+id/name_input" 
    android:hint="ex)안드로이드"/>
</LinearLayout>

<LinearLayout android:layout_height="wrap_content" 
    android:layout_width="fill_parent" 
    android:orientation="horizontal" 
    android:id="@+id/digit_layout">

<TextView android:layout_height="wrap_content" 
    android:layout_width="wrap_content" 
    android:text="@string/digit"/>

<EditText android:layout_height="wrap_content" 
    android:layout_width="fill_parent" 
    android:id="@+id/digit_input" 
    android:hint="ex)011-123-4567"/>

</LinearLayout>

<Button android:layout_height="wrap_content" 
    android:layout_width="wrap_content" 
    android:text="@string/input" 
    android:id="@+id/inputinfo" 
    android:layout_gravity="center_horizontal"/>
</LinearLayout>


단순히 액티비티를 호출할 때에는 startActivity(Intent)를 사용했었지만, 액티비티를 호출한 후 결과값을 받기 위해서는 다른 메소드를 사용해야 합니다. 바로 startActivityForResult(Intent intent, int requestCode)입니다.


public void startActivityForResult(Intent intent, int requestCode)
호출당하는 액티비티로부터 데이터를 넘겨받기 위해 사용합니다.
intent - 인텐트
requestCode - 이 액티비티를 호출하는 액티비티가 여러 개가 있을 경우, 어떤 액티비티가 호출했는지를 알기 위해 사용


requestCode는 별로 특이한 것은 아니고, 한 액티비티를 여러 액티비티가 호출해야 할 경우, 호출이 어디에서 일어났는지를 알려주는 인자값입니다.
일단, InformationInput 액티비티를 봅시다. 버튼을 클릭하면 InformationInput 액티비티가 InformationProc 액티비티를 호출해야 하므로, 일단 intent를 생성하고, startActivityForResult()를 통해 InformationProc 액티비티를 실행시킵니다.



InformationProc 액티비티가 실행되면, 사용자로부터 이름과 전화번호를 입력받게 됩니다.
입력이 끝나고, 입력 버튼을 누르면, 입력받은 데이터를 인텐트에 집어넣게 됩니다.
Intent intent = getIntent(); // 이 액티비티를 시작하게 한 인텐트를 호출	
     EditText name_input = (EditText)findViewById(R.id.name_input);	
     EditText digit_input = (EditText)findViewById(R.id.digit_input);
     intent.putExtra("data_name",name_input.getText().toString());	
     intent.putExtra("data_digit", digit_input.getText().toString());	
     setResult(RESULT_OK,intent); // 추가 정보를 넣은 후 다시 인텐트를 반환합니다.	
finish(); // 액티비티 종료

차근차근 하나씩 보도록 하겠습니다.
일단, 첫번째, 인텐트를 생성하는 것을 볼 수 있습니다. 보통, 인텐트를 생성할 때 new 생성자를 써서 인텐트를 생성했던 것에 반해, 여기에서는 getIntent()를 사용하여 인텐트를 불러오고 있습니다. getIntent()메소드는 현재 자신을 호출했던 인텐트를 반환해줍니다.

여기서, 자신을 호출한 인텐트를 받아오는 것은, 아까 예로 들었던 심부를꾼을 생각해보면 쉽게 이해할 수 있습니다. A라는 심부름꾼에게서 물건을 받았는데, B라는 심부름꾼에게 물건을 주면 안되겠죠? 인텐트도 마찬가지입니다. :)

이렇게 해서 인텐트를 생성하면, 이제 EditText로부터 입력한 값들을 받아와야 합니다. findViewById()를 이용하여 레이아웃 객체와 코드상의 객체를 연결한 후, putExtra()메소드를 이용해 정보를 실어줍니다.

intent.putExtra(String name, _value)
name이라는 이름을 가지는 데이터를 인텐트에 첨가합니다.

인텐트에 들어가는 데이터는 "키"의 역할을 하는 name과 그에 해당하는 값인 _value가 짝을 이루어 저장됩니다.
이렇게 저장이 되었다면, 호출된 액티비티가 정상적으로 끝났는지, 비정상적으로 끝났는지 (물건을 제데로 받았는지, 심부름꾼이 왔는지 등등...으로 비유할 수 있겠습니다) 자신을 호출한 액티비티에게 알려주기도 해야 하고, 요청한 데이터도 같이 주어야 합니다.

일단, 호출당한 액티비티가 정상적으로 끝났음을 알리기 위해, setResult(RESULT_OK, intent) 메소드를 사용합니다. RESULT_OK로 액티비티가 정상적으로 끝났음을 전달하게 됩니다. RESULT_OK를 반환하지 않고 중간에 비정상적으로 종료되었다면 저 코드를 반환받지 못하므로 뭔가 문제가 있구나 알게 되겠죠? 제데로 종료가 된다면, 아까 우리가 추가로 입력한 데이터를 담은 인텐트도 함께 반환하게 됩니다.

이렇게.. 여기까지 정상적으로 돌아간 후, 호출당한 액티비티(InformationProc)가 finish()메소드에 의해 종료되게 되면, OnActivityResult() 메소드가 호출되게 됩니다. 결과를 기다리고 액티비티를 호출했으니, 액티비티가 종료되었으니 그 결과를 확인해야겠죠??


void onActivityResult(int requestCode, int resultCode, Intent data)
startActivityForResult로 호출한 액티비티가 종료되었을 때 호출됩니다.



protected void onActivityResult(int requestCode, int resultCode, Intent data)
{		super.onActivityResult(requestCode, resultCode, data);
		TextView name_view = (TextView)findViewById(R.id.name_view);
		TextView digit_view = (TextView)findViewById(R.id.digit_view);
		if(resultCode==RESULT_OK) // 액티비티가 정상적으로 종료되었을 경우
		{
			if(requestCode==1) // InformationInput에서 호출한 경우에만 처리합니다.
			{
				// 받아온 이름과 전화번호를 InformationInput 액티비티에 표시합니다.
				name_view.setText(data.getStringExtra("data_name"));
				digit_view.setText(data.getStringExtra("data_digit"));
			}
		}
	}



위의 onActivityResult에서, resultCode가 아까 setResult()에서 액티비티가 정상 종료되었는지를 판단하는 인자값, RESULT_OK를 받게 됩니다. 그래서, 이걸 가지고 적절히 예외 처리를 해 줄 수 있는 거죠.
requestCode는 아까 startActivityForResult()를 호출할 때, InformationInput이 호출한 것임을 표시하기 위해 '1'으로 설정하였으므로, 여기에서 또한 그 코드를 맞춰주어야 제데로 결과값을 받을 수 있습니다.

즉, 정상적으로 액티비티가 종료되었다면 requestCode의 값은 RESULT_OK, resultCode는 1이 됩니다.

이렇게 해서, 모두 정상이라면 인텐트에서 받아온 데이터를 꺼내 화면에 표시합니다.

putExtra() 메소드가 어떤 타입이든 상관없었던 것에 비해, 불러올 때에는 getStringExtra()메소드를 사용하여 문자열 값을 불러오면 됩니다. getStringExtra()뿐 아니라 getIntExtra(), getBooleanExtra() 등 여러 가지가 있으므로 상황에 맞추어 사용하면 됩니다.

이렇게 해서, 화면에 표시되는 TextView의 텍스트 값들이 아까 호출한 액티비티의 값들로 바뀌게 됩니다. :)


이렇게 해서, 인텐트를 통해 액티비티간에 데이터를 주고받는 것에 대해서 알아보았습니다. 이번 강좌는 다른 강좌들과는 다르게 세세한 부분에 대한 설명은 대부분 생략하였습니다. 이 강좌쯤을 보시는 분들은 어느 정도 기초가 되어 있으리라 믿기에, 일부러 안 적었습니다. 게다가 그걸 다 적으면 강좌가 한도끝도 없이 길어지기만 하죠 -_-

현재, 이 코드는 모든 문자열 값을 strings.xml에 넣어서 그 쪽에 있는 값들을 참조하는 형식으로 구성되어있습니다. 이 부분에 대해 궁금하신 분은 제가 2009/03/14 - [안드로이드/안드로이드 입문] - [강좌] 외부 리소스 사용하기 (문자열) 에 정리해놓았으니, 이걸 보시면 되겠습니다. :)