본문 바로가기

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

어플리케이션 컴포넌트의 실행 : 인텐트(Intent)


어플리케이션이 한 가지의 액티비티만으로 이루어지는 경우는 거의 없습니다, 대부분 여러개의 액티비티, 서비스 등으로 구성되어 각 컴포넌트들을 호출하여 필요한 작업을 수행하는 구조를 이루고 있죠. 당장 주소록 어플리케이션만 해도 저장된 사람들을 보여주는 액티비티, 새 주소록을 추가하는 액티비티 등 여러 가지의 액티비티로 구성되어 있습니다.

어떤 컴포넌트에서 다른 컴포넌트를 호출하려면 "다른 컴포넌트를 호출하고 싶다"는 의사표현을 해야 합니다. 의사표현을 하려면 공통된 규약에 맞춰 이야기를 해야 합니다. 한 국가에서 하나의 언어를 사용하여 의사소통을 하는 것과 동일하죠.

안드로이드에서는 이러한 "의사표현"의 수단으로 인텐트 객체를 사용합니다.

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

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

방금 설명했던 것처럼 결과값을 반환할 때 쓰이는 인텐트는 사용자가 직접 호출 대상을 지정하는 작업은 없지만 자신을 호출했던 컴포넌트에게 결과값을 돌려주는 것이니 명시적 인텐트라 할 수 있겠죠? 그럼, 요 두가지 인텐트의 종류에 대해 하나씩 자세히 알아보도록 하죠.


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

명시적 인텐트를 만드는 방법은 아래와 같습니다.

Intent intent = new Intent(this, SubActivity.class)


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

packageContext : 현재 컴포넌트를 포함하는 컨텍스트 객체
cls : 호출할 컴포넌트의 클래스


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

이렇게, 명시적 인텐트는 호출할 컴포넌트를 "콕" 집어주기에 어려운 것이 별로 없습니다. 이렇게 인텐트를 생성한 후, startActivity() 혹은 startService() 등의 메소드를 호출하여 호출하려는 컴포넌트의 유형에 맞게끔 인텐트를 넘겨주면 해당 컴포넌트를 호출할 수 있습니다.



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

// 인텐트 객체 생성
Intent intent = new Intent(this, SubActivity.class);

// 액티비티 실행
startActivity(intent);

//결과값을 받기 위한 액티비티 실행
int REQUEST_CODE = 1; // 결과값을 요구하는 여러 상황을 호출 대상 액티비티에서 알게끔 합니다.
startActivityForResult(intent, REQUEST_CODE); // 액티비티 호출


호출한 액티비티에서 결과값을 받은 후, 그 결과는 Activity 클래스 내의 onActivityResult() 메소드를 오버라이드 한 후 처리하게 됩니다. 자세한 것은 2009/03/14 - 인텐트(Intent) 입문- (2) 액티비티간 데이터 주고받기 를 참조하세요.


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


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

1. 넌 뭘 할 수 있니? - action, category

action은 "행동"을 뜻합니다. 즉, 호출 대상 컴포넌트가 처리해줬으면 하는 작업이 action에 정의됩니다. 액션에는 안드로이드 시스템에서 사용하는 액션 외에도 사용자가 직접 액션 이름을 지정한 후 그 액션을 사용할 수도 있습니다. 안드로이드에서 사용하는 액션은 아래와 같은 것들이 있습니다.


ACTION_MAIN의 설명이 조금 생소하신 분들은 2009/09/20 - 액티비티와 태스크(Task) 를 참조하세요. :)

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


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

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

인텐트 필터는 자신이 원하는 인텐트를 골라낼 때 필요한 정보들을 정의해놓은 것으로, 암시적 인텐트의 인텐트 해석(Intent Resolving) 과정에 꼭 필요한 요소입니다. 인텐트 필터에 대한 설명은 잠시 후에 들어가도록 하겠습니다.

<activity android:name=".LifeCycleTester"
                  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");


여기까지 인텐트의 종류 및 인텐트 객체에 들어가는 정보들에 대해 알아보았습니다. 다음 글에서는 이러한 인텐트 객체들이 인텐트 해석 과정을 거치고, 인텐트 필터와 비교하여 정확한 컴포넌트를 호출하는 과정에 대해 알아보도록 하겠습니다. :)