Android 인텐트

timothy jeong·2021년 11월 12일
0

Android with Kotlin

목록 보기
35/69

인텐트

안드로이드 앱은 4개의 컴포넌트(액티비티, 브로드캐스트 리시버, 서비스, 콘텐츠 프로바이더)를 이용하여 개발하는데, 이때 핵심 클래스가 Intent 이다. 인텐트는 '컴포넌트를 실행하려고 시스템에 전달하는 메시지' 라고 정의할 수 있으며, 기능을 수행하는 함수를 제공하는 클래스가 아니라 데이터를 담는 클래스이다. 이 데이터는 컴포넌트를 실행하는 정보이며 이 정보가 담긴 인텐트 객체를 시스템에 전달하면 컴포넌트가 실행된다.

ActvityA 가 실행된 뒤 ActivityB 가 실행된다고 할때, A 에서 B 로 전환한다면 ActivityB 클래스를 생성해서 실행하면 될것 같다. 하지만 액티비티는 컴포넌트 클래스이므로 시스템이 생성해서 실행하지, 개발자가 임의로 생성할 수 없다.

결국 ActivityA 클래스에서 ActivityB 클래스를 실행하려면 시스템에 '내가 이렇게 하고자 한다' 라고 인텐트를 통해 알려줘야한다. 그러면 시스템에서 인텐트의 정보를 분석해서 그에 맞는 컴포넌트를 실행한다.

이러한 인텐트의 중개 역할은 같은 앱의 컴포넌트 뿐만 외부 앱의 컴포넌트와 연동할 때도 마찬가지이다. 즉, A 앱의 컴포넌트에서 인텐트를 시스템에 전달하고, 시스템에서는 그 정보를 분석하여 B앱의 컴포넌트를 실행할 수 있다.

코드로는 인텐트를 만들고, 이를 startActitivt 의 인자로 전달하면 된다.

val intent: Intent = Intent(this, ActivityB::class.java)
startActivity(intent)

컴포넌트와 메니페스트 파일

시스템은 런타임 때 메니페스트 파일에 등록된 컴포넌트 정보를 읽는다. 이때 파악한 정보를 통해서 앱의 컴포넌트가 인텐트로 어떠한 컴포넌트를 요청했을 때 시스템이 실행할 수 있는 것이다. 따라서 컴포넌트를 만들면 메니페스트 파일에 등록해야한다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.ch12practice">

    <application ...>
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

엠티 템플릿으로 만들면 MainActivity 라는 액티비티가 메니페스트에 등록되어 있는 걸 알 수 있다.

인텐트 엑스트라 데이터

ActivityA 에서 ActivityB 를 실행해야하는데 추가적인 데이터를 전달해야 한다면 어떻게 해야할까? 개발자가 컴포넌트 객체에 직접 접근할 수 없기 때문에 시스템에 데이터를 전달하는 방법을 이용해야 한다.

인텐트에 컴포넌트 실행을 요청할 때 데이터를 함께 전달하려면 엑스트라 데이터(extra data) 를 이용해야 한다. 엑스트라 데이터는 인텐트에 담는 부가 정보이다. 이때 Intent 클래스에 정의 되어있는 putExtra 함수를 이용할 수 있다.

val intent: Intent = Intent(this, ActivityB::class.java)
intent.putExtra("data1", "HelloWolrd~")
intent.putExtra("data2", 10)
intent.putExtra("data3", 11.1)
startActivity(intent)

첫번째 인자는 데이터 식별자이며, 두번째 인자가 데이터이다. 이렇게 엑스트라 데이터를 받아서 실행된 컴포넌트는 엑스트라 데이터를 가져오기 위해서 자신을 실행한 인텐트 객체를 얻어야 한다.

    override fun onCreate(savedInstanceState: Bundle?) {
        val intent = intent
        val data1 = intent.getStringExtra("data1")
        // getIntExtra(name: String, defaultValue: Int)
        val data2 = intent.getIntExtra("data2", 0)
        val data3 = intent.getDoubleExtra("data3", 0.0)
        ...
    }

인텐트 필터

val intent: Intent = Intent(this, ActivityB::class.java)

인텐트를 만들때 실행할 대상 컴포넌트를 클래스 타입 레퍼런스로 만드는 것이다. 같은 앱의 컴포넌트라면 이렇게 클래스 타입 레퍼런스로 설정할 수 있지만, 외부 앱의 컴포넌트는 이렇게 실행할 수 없다.

위와 같이 클래스 타입 레퍼런스 정보를 활용해 만든 인텐트를 '명시적 인텐트'라고 하며 이번에 소개할 인텐트 필터 정보를 활용해 만든 인텐트를 '암시적 인텐트' 라고 한다. 외부 앱의 컴포넌트는 암시적 인텐트를 이용해서 만든다.

암시적 인텐트는 메니페스트 파이렝 선언된 인텐트 필터를 이용해서 만든다.

<activity android:name=".OneActivity"/>
<activity android:name=".TwoActivity"
        android:exported="true">
        <intent-filter>
            <action android:name="ACTION_EDIT"/>
        </intent-filter>
</activity>

안드로이드 시스템은 메니페스트 파일의 내용을 참조하여 앱을 실행한다. 그런데 개발자가 처럼 액티비티의 클래스 이름만 설정하면 시스템에는 이름만 등록된다. 따라서 이렇게 등록된 액티비티는 명시적 인텐트에만 이용될 수 있다. 앱 내부에서만 사용할 컴포넌트라면 android:name 속성만 지정해주면 된다.

그런데 앱 외부에서도 인텐트를 실행할 수 있게 해줘야한다면 해당 컴포넌트가 있는 앱의 메니페스트 파일에 암시적 인텐트로 실행할 수 있게 intent-filter 를 설정해줘야 한다.

인텐트 필터 속성 필드

intent-filter 는 activiy, service, receiver 등 컴포넌트 등록 태그 하위에 작성 할 수 있다. 인텐트 필터 하위에는 action, category, data 태그를 이용해 정보를 설정할 수 있다. 어떤 정보를 설정할 것인지는 개발자의 선택이다. action 만 선언할 수도 있고, data 를 함께 선언할 수 있다. 각 태그에 설정하는 값은 아래의 의미를 갖는다.

  • action : 컴포넌트의 기능을 나타내는 문자열이다.
  • category : 컴포넌트가 포함되는 범주를 나타내는 문자열이다.
  • data : 컴포넌트에 필요한 데이터 정보이다.

이들은 개발자가 임의로 지정하는 것이므로 앱에서 유일할 필요가 없다. 그런데 일정한 규칙을 가지고 작성한다. 액션의 경우 android.intent.action.{컴포넌트의 기능} 처럼 작성하고, category 역시 android.intent.category.LAUNCHER (런처가 실행), android.intent.category.BROWSABLE (브라우저가 실행) 식으로 작성한다.

data 는 URL 형식으로 표현하며, action 이나 category 처럼 문자열 하나로 선언하지 않고 android:scheme, android:host, android:port, android:mimeType 등의 속성을 이용한다.

profile
개발자

0개의 댓글