본문 바로가기
Programming/Android Java

인텐트(Intent)와 인텐트 필터 (Intent Filter)

by 개Foot/Dog발?! 2014. 8. 31.

URL1 : http://androidhuman.tistory.com/261

URL2 : http://androidhuman.tistory.com/262


.....


안드로이드에서 '인텐트'라 하면 일반적으로 인텐트 객체를 뜻합니다. 인텐트 객체는 안드로이드 어플리케이션 내의 컴포넌트를 호출하기 위한 여러 정보들을 담고 있으며, 이 정보들에는 호출 대상 컴포넌트의 이름이 명시되어 있을 수도 있고, 혹은 호출 대상 컴포넌트의 특성만 나열되어 있을 수도 있습니다. 또한, 어플리케이션 호출 외에도 호출된 액티비티가 자신을 호출한 액티비티에게 결과값 등을 전달할 때에도 인텐트 객체에 데이터를 담아 전달합니다


.....


이러한 인텐트를 종류별로 분류해보면, 호출 대상 컴포넌트의 이름이 명시되어 있는 인텐트, 즉 어떤 것을 호출해야 할지 명시되어 있는 인텐트를 명시적 인텐트(Explicit Intent), 라 하고, 호출 대상 컴포넌트가 정확히 정해진 것이 아니라 호출 대상 컴포넌트의 특성만 나열되어 있는 인텐트를 암시적 인텐트(Implicit Intent)라 합니다. 



1. 명시적 인텐트 (Explicit Intent)


Intent intent = new Intent(this, TargetActivity.class);


API

public Intent (Context packageContext, Class<?> cls) 


packageContext : 현재 컴포넌트를 포함하는 컨텍스트 객체

cls : 호출할 컴포넌트의 클래스 


인텐트 객체 생성자의 첫번째 인자는 호출하는 컴포넌트의 컨텍스트 객체를 의미하며, getApplicationContext() 메소드를 통해 어플리케이션의 컨텍스트를 넘겨주는 것도 가능합니다. 위의 코드에서는 TargetActivity라는 이름을 가진 컴포넌트를 호출하기 위한 인텐트를 생성하는 것을 확인할 수 있습니다. 


.....


이렇게 인텐트를 생성한 후, startActivity() 혹은 startService() 등의 메소드를 호출하여 호출하려는 컴포넌트의 유형에 맞게끔 인텐트를 넘겨주면 해당 컴포넌트를 호출할 수 있습니다.


..... 액티비티를 호출하는 코드입니다. 첫번째는 그냥 단순히 액티비티를 호출하기만 하는 코드, 두번째는 액티비티를 호출한 후, 호출한 액티비티로부터 결과값을 받을 수 있게끔 호출하는 코드입니다. 


// 인텐트 객체 생성

Intent intent = new Intent(this, TargetActivity.class);

 

// 액티비티 실행

startActivity(intent);

 

//결과값을 받기 위한 액티비티 실행

int REQUEST_CODE = 1; 

// 결과값을 요구하는 여러 상황을 호출 대상 액티비티에서 알게끔 합니다.

startActivityForResult(intent, REQUEST_CODE); 

// 액티비티 호출 


2. 암시적 인텐트 (Implicit Intent)


..... 호출할 컴포넌트를 정확히 아는 것이 아니라 인텐트 객체 내에 호출 대상 컴포넌트를 찾을 수 있는 정보들만 들어있죠. 인텐트 객체 내의 이러한 정보들은 호출 대상 컴포넌트가 "어떤 작업을 처리할 수 있는지", "어떤 유형의 데이터를 처리할 수 있는지" 그리고 "처리할 데이터가 있는 주소"를 주로 담고 있습니다.


1. action, category

.....

액션에는 안드로이드 시스템에서 사용하는 액션 외에도 사용자가 직접 액션 이름을 지정한 후 그 액션을 사용할 수도 있습니다. 안드로이드에서 사용하는 액션은 아래와 같은 것들이 있습니다.


.....

category는 보통 "분류"라는 뜻으로 많이 쓰입니다. 인텐트의 카테고리도 이와 비슷하게 쓰이기는 하지만, 여기서 카테고리는 "분류" 보다는 액션(action)을 보충해주는 속성으로 보는 것이 더 적합합니다.



CATEGORY_LAUNCHERACTION_MAIN과 세트메뉴라 할 수 있습니다. 두 속성이 모두 만나야만 Application Launcher에 아이콘이 표시되고, 그 아이콘을 누르면 실행될 루트 액티비티를 설정할 수 있죠. 


어떤 어플리케이션이건 간에, 어플리케이션이 시작할 때 처음으로 실행되는 액티비티는 메니페스트 파일의 인텐트 필터에 아래와 같이 정의되어있음을 확인할 수 있습니다. 


.....


<activity android:name=".TargetActivity"

                  android:label="@string/app_name">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity> 


2. data


data는 호출 대상 액티비티가 처리해줬으면 하는 데이터의 "주소" 입니다. (실제 데이터가 아닙니다) 이러한 주소는 URI(Uniform Resource Identifier) 형식으로 정의되어있으며, 전화번호, 웹 주소, 데이터의 주소 등 다양한 형태가 있을 수 있습니다.


URI(Uniform Resource Identifier)


URI는 어떤 자원을 나타내는 유일한 주소입니다. URL(Uniform Resource Location) 또한 URI의 하위개념이구요. 인터넷의 특정 페이지를 나타내는 주소가 URL인것과 마찬가지로, 안드로이드 시스템 내의 자원의 주소를 표현하는 하나의 방식입니다. 


data의 유형들은 아래와 같은 것들이 있습니다.



3. type (mimeType)


인텐트 객체 내의 데이터는 데이터의 "주소" 만을 나타낼 뿐, 주소 자체에서 해당 URI가 가리키는 데이터의 종류가 어떤 것인지는 알 길이 없습니다.

.....

즉,  type은 데이터의 "종류"를 지정하여 인텐트 해석 과정에서 정확하게 대상 컴포넌트를 찾을 수 있도록 해줍니다. 따라서 data와 type은 별도의 속성이 아닌 하나의 속성이라 볼 수 있습니다. (실제 인텐트 필터의 data 태그 내에 mimeType 속성이 존재합니다.)


아래 코드에서 인텐트 객체에 type 속성을 추가하는 것을 볼 수 있습니다. 이는 전화번호부 데이터를 받기 위한 속성을 추가하는 것입니다.


Intent intent = new Intent();

intent.setType("vnd.android.cursor.item/phone");


4. extra


Extra는 인텐트 객체에 실제로 데이터를 첨부하여 보내는 것을 의미합니다. 이 데이터들은 키-값 쌍을 이루어 인텐트 객체에 저장되며, putExtra() 메소드를 통해 인텐트 객체에 데이터를 집어넣고, getInt(), getFloat(), getString() 과 같은 메소드로 해당 타입으로 저장된 추가 데이터들을 불러올 수 있습니다.


Intent i = new Intent();

i.putExtra("TEST", "Test string"); 

// String을 넣습니다.

.

.

.

// 인텐트를 받은 다른 컴포넌트가 Extras 데이터를 받아옵니다.

String str = getIntent().getExtras().getString("TEST"); 




[인텐트 필터 (Intent Filter)]


.....


안드로이드 시스템 내부에서는 수많은 어플리케이션들에 의해 수많은 인텐트들이 발생합니다. 이 중에서 자신에게 필요한 인텐트만을 받기 위해 인텐트 필터가 있는 것이죠. 


인텐트 필터가 없다고 해서 인텐트를 받을 수 없는 것은 아닙니다. 인텐트 필터는 인텐트 해석 과정이 필요한 암시적 인텐트(Implicit Intent)를 받을 때만 필요할 뿐, 호출 대상 컴포넌트가 명시되어있는 명시적 인텐트(Explicit Intent)는 이러한 인텐트 필터가 없어도 대상 컴포넌트를 호출할 수 있습니다.


.....


다른 사람이 만든 컴포넌트의 이름을 알기란 어렵습니다. 즉, 명시적 인텐트를 사용하여 해당 컴포넌트를 호출할 수가 없죠. 따라서 암시적 인텐트를 통해 컴포넌트를 호출하게 됩니다. 


암시적 인텐트를 사용하는 이유는 이 뿐만이 아닙니다. 안드로이드가 다른 시스템과 다른 것 중 또 하나는 바로 Native 어플리케이션 (Home, Dialer 등...)까지도 사용자가 별도로 제작한 것으로 대체할 수 있다는 것입니다. 


.....


인텐트 필터의 구성요소


.....



인텐트 필터는 인텐트 객체 내의 정보들을 바탕으로 인텐트를 필터링하기에 인텐트 객체 내의 정보들을 바탕으로 자신이 받을 수 있는 정보들을 정의하며. 이 정보들 중 인텐트 필터에서 주로 필터링하는 항목은 action, data (데이터 주소 유형 및 데이터 타입), category입니다.


이러한 인텐트 필터의 내용들을 어플리케이션이 실행되기 전에 안드로이드 시스템에서 알고 있어야 다른 어플리케이션에서 해당 어플리케이션의 컴포넌트를 필요로 하는 인텐트를 발생시켜도 해당 컴포넌트를 실행시킬 수 있습니다. 때문에, 이러한 인텐트 필터의 내용들은 메니페스트 파일인 AndroidManfest.xml 파일의 각 컴포넌트 태그 내에 정의됩니다.


<activity android:name=".TargetActivity"

          android:label="@string/app_name">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>


** 위의 AndroidManifest.xml 파일을 통해서 정의할 수도 있지만,

IntentFilter 의 객체를 통해 코드상으로 Filter의 특성을 정의하고

Context class의 registerReceiver() 함수를 통해 리시버를 만들면서 Filter를 코드를 통해 시스템에 등록할 수 있다.

특히 AndroidManifest.xml에 등록할 수 없는 Intent action들을 코드상으로 등록해서 사용하기도 한다. 


1. action(액션) 필터


인텐트 객체 내의 action을 검사하여 인텐트 필터에 정의된 액션과 일치하는지 여부를 검사합니다. 이 검사를 통과하려면 인텐트 객체 내의 액션이 인텐트 필터에 정의된 액션과 일치해야 합니다. 단, 인텐트에 액션이 아예 정의되어있지 않은 경우에는 액션 필터를 통과할 수 있습니다.


.....


2. category (카테고리) 필터


인텐트 객체 내의 category 항목을 검사하여 인텐트 필터에 정의된 카테고리와 일치하는지 여부를 검사합니다. 액션 검사에서는 인텐트 객체 내에 아예 액션이 정의되어있지 않은 경우 액션 검사를 통과할 수 있었던 것에 반해 카테고리 검사는 인텐트 객체에 정의된 카테고리가 인텐트 필터에 정의된 카테고리들과 일치해야 합니다. 


.....


이 때문에, 암시적 인텐트를 만들 때 카테고리를 추가하지 않을 경우 안드로이드에서 자동으로 CATEGORY_DEFAULT(android.intent.category.DEFAULT)를 추가해주게 됩니다. 때문에 카테고리를 특별히 추가해주지 않은 인텐트를 받을 수 있게 하려면 카테고리 필터에 android.intent.category.DEFAULT 를 추가해줘야 합니다. 그렇지 않으면 어떠한 암시적 인텐트도 받을 수 없게 됩니다.



3. data (데이터) 필터


인텐트 객체 내의 data 항목 및 type을 검사하여 인텐트 필터에 정의된 값과 비교하여 일치 여부를 검사합니다.

데이터 검사는 크게 데이터의 주소(URI)를 검사하는 부분과 데이터의 유형(type, MIME type)을 검사하는 부분으로 나누어집니다. 


데이터의 주소를 검사하는 부분은 데이터의 주소를 세분화하여 검사할 수 있도록 되어있습니다. URI(Uniform Resource Identifier)는 다음과 같은 구조로 구성되어있습니다.


 scheme://host:port/path


만약, http://google.com 을 각 요소별로 나누어본다면 scheme는 http, host는 google.com 이 되겠죠? 이와 마찬가지로 안드로이드 시스템에서 사용하는 주소들도 각각의 요소들로 나눌 수 있습니다. 
예를 들어 content://com.androidhuman.provider.SimpleMemo/memos/1 같은 주소의 경우 scheme는 content, host는 com.androidhuman.provider.SimpleMemo, path는 memos/1 이 되겠지요??
데이터의 유형을 필터링하는 것은 type(mimeType)을 이용합니다. 보통 아래와 같이 정의됩니다.


<data android:mimeType = "video/mpeg" android:scheme = "http">

<data android:mimeType = "audio/*" android:scheme = "http"> 


mimeType은 위와 같은 형식으로 정의되며, 큰 범주/큰 범주의 하위 범주 형식으로 정의됩니다. (video/mpeg의 경우 큰 범주가 video, video의 하위 범주가 mpeg) 하위 범주에는 와일드카드 문자(*) 를 사용하여 해당 범주 내의 모든 형식을 허용할 수도 있습니다.


이런 방식으로 첫번째 <data> 필터를 해석하면 "http 스키마를 가진 mpeg 형식의 비디오 데이터"를 가진 인텐트를 허용하는 것임을 알 수 있고, 두번째 필터는 "http 스키마를 가진 모든 오디오 데이터"를 가진 인텐트를 허용하는 것임을 알 수 있습니다.


.....