Android

[안드로이드]Intent에 관하여

나맘임 2023. 6. 1. 01:27

Intent(인텐트)란?

메시징 객체로, 다른 앱 구성 요소로부터 작업을 요청하는 데 사용할 수 있는 것

여기서 앱 구성 요소는 안드로이드 어플리케이션을 구성하는 기본 요소를 의미하며, Activity, Service, Broadcast Receiver, Content Provider가 있습니다.

 

쉽게 말해, 기본 요소들끼리 정보 전달을 해주는 것이자 앱에서 작업을 수행하기 위해 사용하는 전달 수단입니다.

 

Intent 사용 사례

공식 문서에서 설명하는 Intent를 사용하는 경우는 다음과 같습니다.

1. Activity(액티비티) 시작

Activity는 앱 안의 단일 화면을 나타냅니다. Activity의 새 인스턴스를 시작하기 위해 Intent를 startActivity()로 전달하는데,

이 Intent는 시작할 Activity의 정보(필수 데이터)를 담고 있습니다.

 

Activity가 완료되면, startActivityForResult()가 호출되어 액티비티는 이 메소드의 결과를  onActivityResult() 콜백에서 별도의 Intent 객체로 수신하게 됩니다.

2. Service 시작

Service는 사용자 인터페이스 없이 백그라운드에서 작업을 수행하는 구성 요소입니다.

API 레벨 21 이상이면 JobScheduler 클래스를 사용하여 서비스를 실행하며 이 때, Intent를 전달하게 됩니다.

이 Intent는 1번 사례와 마찬가지로 시작할 서비스의 필수 데이터를 담고 있습니다.

3. Broadcast 전달

Broadcast는 모든 앱이 수신할 수 있는 메시지로 시스템은 부팅될 때 또는 기기가 충전을 시작할 때와 같은 시스템 이벤트가 발생하게 되면 Broadcast를 전달하게 됩니다.

 

이 때, Intent를 sendBroadcas() 또는 sendOrderBroadcast()에 전달하게 됩니다.

 

Intent 유형

Intent는 크게 두 유형이 존재합니다.

1. 명시적 Intent

인텐트를 충족하는 애플리케이션이 무엇인지 지정하는 방식

이를 위해 대상 앱의 패키지 이름 또는 완전히 자격을 갖춘 구성 요소 클래스를 이름을 제공합니다.

일반적으로 앱 안에서 구성 요소를 시작할 때 사용합니다.

val intent2 = Intent(context, AlarmService::class.java)

다시 말해, 명시적 Intent은 의도가 명확하고, 패키지 명과 클래스 명을 정확하게 명시합니다.

 

2. 암시적 Intent

특정 구성 요소의 이름을 대지 않지만, 그 대신 수행할 일반적인 작업을 선언하여 다른 앱의 구성 요소가 이를 처리할 수 있도록 해줍니다.

 

암시적 Intent는 호출할 대상이 명확하지 않을 때 사용하며, 인텐트의 의도와 맞는 액티비티를 찾아서 실행합니다.

fun createAlarm(message: String, hour: Int, minutes: Int) {
    val intent = Intent(AlarmClock.ACTION_SET_ALARM).apply {
        putExtra(AlarmClock.EXTRA_MESSAGE, message)
        putExtra(AlarmClock.EXTRA_HOUR, hour)
        putExtra(AlarmClock.EXTRA_MINUTES, minutes)
    }
    if (intent.resolveActivity(packageManager) != null) {
        startActivity(intent)
    }
}

 

주로  intent.resolveActivity(packageManager)을 통해 검사 후 사용하게 됩니다.

 

암시적 Intent는 사용하게 되면 안드로이드 시스템이 인텐트 필터를 사용하여 적절한 액티비티를 찾게 됩니다.

 

인텐트 필터란?

 

매니페스트 파일에 들어 있는 것으로, 구성 요소가 수신하고자 하는 인텐트의 유형이 정의되어 있습니다.

Intent를 이 인텐트 필터와 비교하여 일치하게 된다면 시스템에서 해당 구성 요소를 시작하고 Intent 전달하게 됩니다.

<activity ...>
    <intent-filter>
        <action android:name="android.intent.action.SET_ALARM" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

 

암시적 인텐트 실행 과정

 

Intent 빌드

위에서 언급했다싶이 Intent 에는 시스템이 어느 구성 요소를 시작할지 판별하는 데 사용하는 정보가 담겨 있습니다.

Intent 에 포함된 기본 사항은 다음과 같습니다.

 

1. 구성 요소 이름

시작할 구성 요소의 이름입니다.

필수 항목이 아니라 선택 항목이지만, 명시적 Intent를 사용할 땐 중요한 정보가 됩니다.

다시 말해, 이 인텐트는 구성 요소 이름이 정의한 앱 구성 요소에만 전달되어야 한다는 뜻입니다.

구성 요소 이름이 없으면 암시적 Intent가 되는 겁니다.

 

참고!
Service의 경우엔 항상 구성 요소 이름을 지정해야 합니다!
그렇지 않으면 Intent에 어느 서비스가 응답할 지 확신할 수 없게 되기 때문입니다.

ComponentName 객체로 구성되어 있고, 지정하기 위해선 구성 요소의 완전히 정규화된 클래스 이름(앱의 패키지 이름까지!) 사용해야 합니다. 예를 들어 com.example.StartActivity 와 같이 적어야 한다는 겁니다.

 

2. 작업

수행할 작업을 나타내는 문자열입니다.

참고!
Broadcast 경우, 이 문자열을 기본적으로 사용하고 있습니다!

 이 작업은 대체로 나머지 Intent의 구조를 결정하게 되는데, 특히 데이터와 엑스트라가 결정됩니다.

 

일반적으로 Intent 클래스나 다른 프레임워크 클래스가 정의한 작업 상수를 지정하지만, 사용자가 직접 지정할 수도 있습니다.

 

다음은 액티비티를 시작할 때 사용하는 보편적인 작업입니다.

 

(1) ACTION_VIEW

액티비티가 사용자에게 표시할 정보를 가지고 있을 때, startActivity()가 있는 인텐트에서 사용합니다.

예를 들자면, 갤러리 앱에서 사진을 보는 경우입니다.

 

(2) ACTION_SEND

공유 인텐트라고 불리며, 사용자가 다른 앱을 통해 공유할 수 있는 데이터를 가지고 있을 때, startActivity()가 있는 인텐트에서 사용합니다.

 

const val ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL"

 

3. 데이터

작업을 수행할 데이터 및 해당 데이터의 MIME 유형을 참조하는 URI입니다.

쉽게 말해 제공할 데이터의 유형을 나타내는 부분입니다.

 

4. 카테고리

Intent를 처리해야 하는 구성 요소의 종류에 관한 추가 정보를 담은 문자열입니다.

필수 항목은 아니며, 설명을 넣기 위해 사용합니다.

 

다음은 보편적인 카테고리들 중 하나 입니다.

(1) CATEGORY_BROWSABLE

액티비티가 웹브라우저를 통해 시작되도록 허용하고 이미지, 이메일 등의 링크로 참조된 데이터를 표시할 때 사용합니다.

 

(2) CATEGORY_LAUNCHER

이 액티비티가 최초의 액티비티이며, 시스템 애플리케이션 시작 관리자에 목록으로 게재합니다.

 

5. 엑스트라(Extra)

요청된 작업을 수행하는 데 필요한 추가 정보가 담긴 키-값 쌍입니다.

putExtra() 메서드를 통해 엑스트라 데이터를 추가할 수 있습니다.

모든 엑스트라 데이터들을 Bundle 객체로 만든 다음 Bundle을 Intent에 putExtras() 로 삽입할 수도 있습니다.

data class SimpleData(
    val name : String
) : Serializable

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

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

        val bundle = Bundle()
        bundle.putSerializable("key", SimpleData(name = "hi"))
        intent.apply {
            this.putExtra("bundle", bundle)
        }

        startActivity(intent)

    }
}
class MainActivity2 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)

        val bundle = intent.getBundleExtra("bundle")
        val simpleData = bundle?.getSerializable("key") as SimpleData
    }
}
참고!
프로세스 간 객체를 전달하기 위해선 직렬화가 필요합니다.
이 때 Serializable 또는 Parcelable를 사용하여 직렬화를 거칩니다.