activity에서 인스턴스를 전달할때 intent의 사용을 하곤했는데요. 그외에도 intent를 사용해서 인스턴스를 전달하게 될 때를 알아보겠습니다.
Activity
Activity가 시작하게 될때 intent에 context 및 실행할 actvity 와 필수 데이터를 담아서 전송하고 있습니다. startActivty()
에서 activity를 실행할때와 activity에서 완료 결과를 받을수 있는 (현재 deprecated 되었으며 activity 결과를 요청하기 위해서는 새로운 개념인 onActivityResult()
를 사용할때 intent를 사용합니다.ActivityResultLauncher
의 intent를 사용합니다)
Service
사용자 인터페이스를 제공하지 않고 백 그라운드에서 작업하는 구성요소입니다. 21버전 이후로는 JobScheduler
로 서비스를 실행할 수 있습니다. 파일다운로드와 같은 일회성 작업에 주로 사용되고 있습니다. startService()
를 사용할때 intent를 사용합니다.
Broadcasting
모든 앱이 수신할 수 있는 메시지로 시스템 부팅 및 기기 충전 시작과 같은 시스템 이벤트에 전달할 수 있습니다. sendbroadcast()
와 sendOrderedBroadcast()
에서 intent를 사용합니다.
다양한 용도로 intent에 데이터를 담아 전달하고 있습니다. intent의 사용방법으로 intent를 선언시 명시적 선언을 할경우와 암시적 선언을 하는 경우가 있습니다
명시적 intent는 말 그대로 일반적으로 시작하려는 구성요소의 정확한 클래스 이름이 정의된 명시적 intent를 사용하여 activity를 이동하는 것을 말합니다
// Executed in an Activity, so 'this' is the Context
// The fileUrl is a string URL, such as "http://www.example.com/image.png"
val downloadIntent = Intent(this, DownloadService::class.java).apply {
data = Uri.parse(fileUrl)
}
startService(downloadIntent)
암시적 intent는 명시적 intent와는 다르게 구성요소를 사용할때 정확한 클래스가 아닌 실행할 작업을 선언합니다. 작업은 보기, 수정, 보내기 또는 가져오기와 같이 원하는 동작을 지정합니다.
// Create the text message with a string
val sendIntent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, textMessage)
type = "text/plain"
}
// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(packageManager) != null) {
startActivity(sendIntent)
}
앱이 수신할 수 있는 암시적 인텐트가 어느 것인지 알리려면, intent-filter요소를 사용하여 각 앱 구성 요소에 대해 하나 이상의 인텐트 필터를 manifest.xml 파일에 선언합니다
<activity android:name="ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
intent-filter는 수신하고자 하는 intent의 유형으로 세가지 유형의 요소가 존재합니다
action
name 특성에서 허용된 인텐트 작업을 선언합니다. 이 값은 어떤 작업의 리터럴 문자열 값이어야 하며, 클래스 상수가 아닙니다.
category
허용된 데이터 유형을 선언합니다. 이때 데이터 URI(scheme, host, port, path)와 MIME 유형의 여러 가지 측면을 나타내는 하나 이상의 특성을 사용합니다.
data
name 특성에서 허용된 인텐트 카테고리를 선언합니다. 이 값은 어떤 작업의 리터럴 문자열 값이어야 하며, 클래스 상수가 아닙니다.
Intent 객체에는 android system에서 어떤 구성 요소를 시작할지를 판별하는 정보가 담겨 있습니다. 구성요소는 다음과 같습니다
시작할 구성 요소의 이름입니다. 선택항목에 해당하는 것으로 구성 요소 이름이 없으면 Implicit-intent가 되며 수신해야 하는 구성 요소는 다른 intent 정보를 기반으로 시스템에서 결정합니다(intent-fliter) 만약 특정 구성 요소를 시작해야 하는 경우에는 구성 요소 이름을 지정해야 합니다. Service를 시작하는 경우에는 구성 요소 이름은 필수로 지정해야 합니다.
Intent의 필드는 ComponentName과 같은 정규화된 클래스 이름을 사용해야 합니다.
수행할 일반적인 작업을 나타냅니다. (보기 또는 선택)
본인 앱 내에 있는 intent가 사용할 작업을 지정할 수도 있지만 보편적으로는 Intent 클래스나 다른 프레임워크 클래스가 정의한 작업 상수를 지정합니다
작업을 수행할 데이터 및 해당 데이터의 MIME 타입을 참조하는 URI
인텐트를 처리해야 하는 구성 요소의 종류에 관한 추가 정보를 담은 문자열
CATEGORY_BROWSABLE
대상 액티비티가 웹브라우저를 통해 시작되도록 허용하고 이미지, 이메일 메시지 등의 링크로 참조된 데이터를 표시하게 합니다.
CATEGORY_LAUNCHER
이 액티비티가 작업의 최초 액티비티이며, 시스템의 애플리케이션 시작 관리자에 목록으로 게재됩니다.
요청된 작업을 수행하는 데 필요한 추가 정보가 담긴 key-value
Intent의 메타데이터와 같은 기능을 하여 액티비티를 시작할 방법에 대한 지침이나 액티비티를 시작한 다음에 어떻게 처리해야하는지에대해서도 알려줄 수 있습니다.
외부 application permission을 허가 하여 안에 들어있는 Intent를 자기 앱의 자체 프로세스처럼 실행하는 것입니다
PendingIntent.getActivity()
PendingIntent.getService()
PendingIntent.getBroadcast()
implicit-Intent를 수신하면 가장 최선의 액티비티를 검색하게 됩니다. 이것은 Intent-filter에 비교할때 작업, 데이터(URI, 데이터 유형), 카테고리 에 대한 측면에 대한 비교를 하게 됩니다. intent-fliter가 manifest에서 어떻게 선언되었는지에 따라 인텐트가 매칭되는 지 살펴보겠습니다.
<intent-filter>
<!-- 작업 테스트 -->
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.VIEW" />
<!-- 카테고리 테스트 -->
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- 데이터 테스트 -->
<data android:mimeType="video/mpeg" android:scheme="http" ... />
<data android:mimeType="audio/mpeg" android:scheme="http" ... />
</intent-filter>
제가 조금 더 검색해보니 ShareCompat라이브러리로 builder 패턴을 사용하여 조금 더 쉽게 데이터를 전달 할 수 있게 암시적 intent를 생성할 수도 있었습니다. 이 부분은 후에 포스팅 하겠습니다.