본문 바로가기

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

암시적 인텐트(Implicit Intent)를 사용해보자!

강좌 작성환경
SDK Version : Android SDK 2.0, release 1
ADT Version : 0.9.4

추후 SDK업데이트로 인해 글의 내용과 실제 내용간 차이가 있을 수 있습니다.


이번 강좌에서는 예제를 통해 여러 암시적 인텐트를 사용하는 방법에 대해 알아보도록 하겠습니다. 이번 예제에서 사용해볼 암시적 인텐트들은 다음과 같습니다.

  • 전화번호 입력(Dial)
  • 전화 걸기 (Call)
  • 오디오 파일 불러오기
  • 전화번호부 데이터 불러오기

예제 어플리케이션은 각 버튼를 누르면 해당 인텐트를 실행하도록 되어있으며, 예제에서 사용된 코드는 다음과 같습니다.

[IntentTester.java]

package com.androidhuman.IntentTester;

package com.androidhuman.IntentTester;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class IntentTester extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Button callButton = (Button)findViewById(R.id.callbutton);
        Button dialButton = (Button)findViewById(R.id.dialButton);
        Button getAudioButtonWithChooser = (Button)findViewById(R.id.getAudioButtonWithChooser);
        Button getAudioButton = (Button)findViewById(R.id.getAudioButton);
        Button getContactsButton = (Button)findViewById(R.id.getContactsButton);
        
        callButton.setOnClickListener(new OnClickListener(){

			public void onClick(View v) {
				Intent i = new Intent(Intent.ACTION_CALL);
				i.setData(Uri.parse("tel:0101234567"));
				startActivity(i);
			}
        	
        });
        
        dialButton.setOnClickListener(new OnClickListener(){

			public void onClick(View v) {
				Intent i = new Intent(Intent.ACTION_DIAL);
				i.setData(Uri.parse("tel:0101234567"));
				startActivity(i);
			}
        	
        });
        
        getAudioButton.setOnClickListener(new OnClickListener(){

			public void onClick(View v) {
				Intent i = new Intent(Intent.ACTION_GET_CONTENT);
				i.setType("audio/*");
				startActivityForResult(i, 0);
			}
        	
        });
                
       getAudioButtonWithChooser.setOnClickListener(new OnClickListener(){

 			public void onClick(View v) {
 				Intent i = new Intent(Intent.ACTION_GET_CONTENT);
 				i.setType("audio/*");
        		startActivityForResult(Intent.createChooser(i, "Select Audio Source..."), 0);
        		}
                	
            });         
        
        
        getContactsButton.setOnClickListener(new OnClickListener(){

			public void onClick(View v) {
				Intent i = new Intent(Intent.ACTION_PICK);
				i.setData(Uri.parse("content://contacts/phones"));
				startActivityForResult(i,0);
			}
        	
        });
    }
    
    protected void onActivityResult(int requestCode, int resultCode, Intent data){
    	super.onActivityResult(requestCode, resultCode, data);
    	if(resultCode == RESULT_OK){
    		Log.i("IntentTester", data.getData().toString());
    	}
    }
}

[main.xml]

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >

<Button android:layout_height="wrap_content" 
	android:id="@+id/callbutton" 
	android:layout_width="fill_parent" 
	android:text="action : ACTION_CALL / data : tel:0101234567"></Button>

<Button android:layout_height="wrap_content" 
	android:layout_width="fill_parent" 
	android:id="@+id/dialButton" 
	android:text="action : ACTION_DIAL / data : tel:0101234567"></Button>

<Button android:layout_height="wrap_content" 
	android:layout_width="fill_parent" 
	android:id="@+id/getAudioButton" 
	android:text="action : ACTION_GET_CONTENT / type : audio/*"></Button>

<Button android:layout_height="wrap_content" 
	android:layout_width="fill_parent" 
	android:text="action : ACTION_GET_CONTENT / type : audio/* / with Chooser" 
        anddroid:id="@+id/getAudioButtonWithChooser"></Button>

<Button android:layout_height="wrap_content" 
	android:layout_width="fill_parent" 
	android:id="@+id/getContactsButton" 
	android:text="action : ACTION_PICK / data : content://contacts/phones"></Button>
</LinearLayout>

IntentTester 액티비티는 데이터를 받아오는 인텐트를 사용했을 때 데이터를 받아오는 것을 확인하기 위해 onActivityResult() 메소드에서 받은 데이터를 LogCat을통해 표시해주도록 하고 있습니다.



또한, 예제에서 전화번호 입력, 전화 걸기 및 주소록에서 데이터베이스를 읽어야 하므로 이에 따른 권한이 필요합니다. 메니페스트 파일에 해당 권한을 추가해주도록 합시다.



우선, 전화번호를 입력(Dial)하는 인텐트와 전화를 거는 인텐트부터 살펴보겠습니다. 

callButton.setOnClickListener(new OnClickListener(){

			public void onClick(View v) {
				Intent i = new Intent(Intent.ACTION_CALL); // 전화를 거는 액션
				i.setData(Uri.parse("tel:0101234567")); // 전화번호를 인텐트에 넣어줍니다.
				startActivity(i); // 해당 인텐트를 처리하는 액티비티 (Dialer) 실행
			}
        	
        });
        
        dialButton.setOnClickListener(new OnClickListener(){

			public void onClick(View v) {
				Intent i = new Intent(Intent.ACTION_DIAL); // 전화번호를 입력하는 액션
				i.setData(Uri.parse("tel:0101234567")); // 전화번호를 인텐트에 추가합니다.
				startActivity(i); // 해당 인텐트를 처리하는 액티비티 (Dialer) 실행
			}
        	
        });


전화를 거는 동작은 액션으로 ACTION_CALL을 가지고, 전화번호를 입력하는 동작은 액션으로 ACTION_DIAL을 가지며, 두 액션 모두 데이터(Data)로 전화를 걸거나 입력할 번호를 필요로 합니다. 보통, 데이터에는 실제 데이터가 아닌 데이터의 주소(URI; Uniform Resource Identifier)가 들어가는데, Dialer, 웹 브라우저, 구글맵 어플리케이션 등에서는 위의 데이터처럼 실제 값을 받게 됩니다. 이와 같이 데이터에 실제 값을 넣는 경우는 Intents List : Invoking Google Applications on Android Devices 를 참고하세요.

이렇게 인텐트에 액션과 데이터를 설정한 후 인텐트를 실행시키면 다음과 같은 화면이 표시됩니다.



ACTION_CALL은 바로 왼쪽 화면처럼 바로 전화가 걸리게 되며, ACTION_DIAL은 오른쪽 화면에서 보는 것처럼, Dialer 액티비티가 호출된 후, 전화번호 입력 창에 우리가 데이터로 넘겨준 전화번호가 입력되어있는 것을 볼 수 있습니다.

다음으로는 오디오 데이터를 불러오는 인텐트를 보도록 하겠습니다.

데이터를 받아와야 하기 때문에 액션은 ACTION_GET_CONTENT, 특정 형식의 오디오 데이터가 아닌 모든 형식의 오디오 데이터를 불러와야 하므로 mimeType을 audio/* 로 지정합니다.

getAudioButton.setOnClickListener(new OnClickListener(){

			public void onClick(View v) {
				Intent i = new Intent(Intent.ACTION_GET_CONTENT);
				i.setType("audio/*");
				startActivityForResult(i, 0);
			}
        	
        });

이 인텐트를 실행시켜 보면, 다음과 같은 화면이 나타나게 됩니다.




현재 오디오 데이터를 받아올 수 있는 컴포넌트로 음악 트랙 선택(Music플레이어)와 Sound Recorder 2개가 있는 것을 알 수 있습니다. 암시적 인텐트는 이런 식으로 해당 작업을 할 수 있는 모든 컴포넌트들을 호출할 수 있습니다. 따라서 인텐트 해석 결과, 위와 같이 해당 데이터를 처리할 수 있는 컴포넌트가 여러 가지인 경우 사용자가 원하는 컴포넌트를 선택하여 액션을 "마무리" 해 줘야 합니다. 

그럼, 바로 아래의 인텐트를 실행시켜볼까요? 

getAudioButtonWithChooser.setOnClickListener(new OnClickListener(){

 			public void onClick(View v) {
 				Intent i = new Intent(Intent.ACTION_GET_CONTENT);
 				i.setType("audio/*");
        		startActivityForResult(Intent.createChooser(i, "Select Audio Source..."), 0);
        		}
                	
            });

이 인텐트를 실행시키게 되면 다음과 같은 화면이 표시됩니다.



여기에서는 인텐트를 실행시킬 때 IntentChooser를 사용하여 인텐트를 처리할 수 있는 컴포넌트가 하나 이상이 되어 여러 컴포넌트 중 하나를 선택할 때 나오는 다이얼로그의 이름을 지정해 줄 수 있습니다. 위와 같이 모든 어플리케이션에서 사용될 수 있는 파일 형식 (이미지, 사진, 비디오 등..)을 가진 데이터를 받아오게 될 경우, 위와 같이 IntentChooser를 사용하여 미리 다이얼로그의 이름을 지정해주는 것이 더 좋겠죠? 

마지막으로, 주소록에서 전화번호를 받아오는 인텐트를 보도록 하겠습니다.

[SDK 1.6 이하]

getContactsButton.setOnClickListener(new OnClickListener(){

			public void onClick(View v) {
				Intent i = new Intent(Intent.ACTION_GET_CONTENT);
				i.setType("vnd.android.cursor.item/phone");
				startActivityForResult(i,0);
			}
        	
        });

위의 인텐트를 실행하면 다음과 같은 화면이 표시되며, 주소록에서 이름을 선택하게 되면 LogCat 화면에 선택한 이름의 전화번호가 저장된 주소(URI)가 표시되게 됩니다.

전화번호부 액티비티가 호출된 화면


DDMS에 선택한 주소록 데이터의 주소가 표시됩니다.



인텐트의 액션은 ACTION_PICK, 데이터로는 content://contacts/phones를 설정하였습니다. 이 인텐트는 전화번호부의 데이터를 받아올 수 있는 인텐트입니다. 

ACTION_PICK은 ACTION_GET_CONTENT와 같이 데이터를 받아올 때 사용하는 액션입니다. 하지만, 두 액션은 부가적으로 필요로 하는 정보에 다소 차이가 있습니다. ACTION_PICK은 부가적으로 필요한 데이터로 데이터의 실제 주소(URI; Uniform Resource Identifier)를 사용하며, ACTION_GET_CONTENT는 데이터의 유형(mimeType)을 사용합니다.

따라서, 일반적으로 이미지, 영상 등 여러 어플리케이션에서 범용으로 사용되는 데이터를 불러올 대는 ACTION_GET_CONTENT 및 해당 데이터의 타입을 가지는 인텐트를 사용하고 전화번호부처럼 특정 어플리케이션에서만 사용하는 데이터를 불러올 경우 ACTON_PICK 및 해당 데이터의 주소를 사용합니다. 하지만, 꼭 이렇게 정해진 것은 아니므로 편의에 따라 ACTION_GET_CONTENT 및 ACTION_PICK 중 하나를 선택하여 사용할 수도 있습니다. 

위의 전화번호부를 받아오는 인텐트는 아래와 같이 ACTION_GET_CONTENT를 사용하도록 만들 수도 있습니다.

Intent i = new Intent(Intent.ACTION_GET_CONTENT);
				i.setType("vnd.android.cursor.item/phones");
				startActivityForResult(i,0);

위의 인텐트를 실행하면 위의 인텐트와 같이 주소록이 표시되게 되며, 이름을 선택하게 되면 위의 ACTON_PICK을 사용한 인텐트와 동일하게 전화번호가 저장되어 있는 주소를 반환합니다.

SDK 2.0 (Eclair) 버전부터는 주소록의 주소가 다소 변경되었습니다. 따라서 위의 코드를 그대로 쓰시면 주소록을 정상적으로 받아올 수 없습니다. 2.0 에서는 다음과 같이 사용하시면 됩니다. 기존의 코드를 그대로 사용하시면 아래와 같이 주소록을 찾을 수 없다는 메시지가 표시됩니다.

				Intent i = new Intent(Intent.ACTION_GET_CONTENT); // ACTION_GET_CONTENT 액션을 사용하는 경우
				i.setType("vnd.android.cursor.item/phone_v2");
				startActivityForResult(i,0);

				Intent i = new Intent(Intent.ACTION_PICK); // ACTION_PICK 액션을 사용하는 경우
				i.setData(Uri.parse("content://com.android.contacts/data/phones"));
				startActivityForResult(i,0);

위의 코드를 사용한 경우

1.6 버전용 코드를 사용한 경우




지금까지, 인텐트의 개념부터 시작하여 특징, 종류 및 실제로 암시적 인텐트를 사용하는 방법까지 알아보았습니다. 여기까지 잘 따라오셨다면 인텐트의 정체(!)에 대해 어느 정도 눈을 뜨셨을겁니다. :)

여기에서 인텐트에 대해 다루는 범위는 여기까지이지만, 이것 외에도 인텐트는 심오한 면들을 많이 가지고 있습니다. 안드로이드 시스템에서 없어서는 안될 핵심적인 역할을 하기도 하구요. 비록 영문이기는 하지만, 인텐트와 관련된 다른 내용들은 Android Developers 사이트의 문서들을 찾아보면 상세히 기술되어 있으니 이 문서들을 정독해보는 것을 추천합니다.