인텐트란 무엇인가요?
인텐트의 종류가 무엇인가요?
그럼 명시적 인텐트와 암시적인텐트의 차이는 뭐고 언제 쓰이나요?
이 질문이 들어오면 오잉? Intent는 안드로이드에서 컴포넌트끼리 데이터 전달하거나 실행시키는것(?) 명시적 intent는 명시적으로 컴포넌트 명들을 적어주는 것(?) 암시적 인텐트는…음 암시적으로!
이런 생각을 하고 있는 나를 발견했다. 막상 말로 표현하려고 하니 어려움… 즉! 정확하게 알지 못하는 것이다.
그래서 시작한 인텐트에 대한 정리!!
정리하면서 보니 처음 안드로이드 Activity간에 화면 전환을 할 때 인텐트를 작성해서 넘겨줬던 파릇파릇하던 내가 떠올랐다.
val intent = Intent(this, ExampleActivity::class.java)
startActivity(intent)
인텐트란?
공식문서에 따르면
Intent는 안드로이드의 컴포넌트(Activity, Service, BroadcastReceiver 등) 간에 데이터를 전달하거나 특정 작업을 요청하기 위한 메시징 객체이다.
대표적인 사용 사례 세가지로는
- 액티비티 시작 (= 화면 전환)
- 서비스 시작 (= 백그라운드 작업 수행)
- 브로드캐스트 전달 (= 시스템 이벤트 전달)
이 있다고 한다.
즉,
<안드로이드 4대 컴포넌트>
- 액티비티 (Activity)
- 서비스 (Service)
- 브로드캐스트 리시버 (Broadcast Receiver)
- 컨텐트 프로바이더 (Content Provider)
얘네들을 실행시키고 사이사이에 데이터를 주고 받기 위해 사용한다.
실행하고자 하는 컴포넌트 정보를 담은 인텐트를 구성해서 시스템에 넘기면 시스템에서 인텐트의 정보를 분석해 맞는 컴포넌트를 실행시켜 준다고 한다.
인텐트 유형
인텐트 유형에는 다른 컴포넌트를 실행 할 때, 어떤 정보들을 인텐트에 담는지에 따라 명시적 인텐트와 암시적 인텐트로 구분된다.
명시적 인텐트
- 실행하고자 하는 컴포넌트 클래스의 이름을 지정한다.
- 그렇기 때문에 일반적으로 앱 안에서 컴포넌트를 시작할 때 쓴다. → 시작하고자 하는 액티비티나 서비스의 클래스 이름을 알고 있기 때문,
- 맨 위에 썼던 ExampleActivity 실행하는 것처럼 사용.
암시적 인텐트
- Intent Filter라는 것을 활용해서 실행한다.
- Intent의 Action에 따라 해당하는 적합한 외부 애플리케이션의 클래스를 호출한다.
- 시스템은 인텐트가 인텐트 필터 중 하나를 통과한 경우에만 암시적 인텐트를 구성요소에 전달한다.
- 웹 브라우저의 호출이나 이메일 전송, 전화앱을 실행하는 데 사용한다.
인텐트 필터
- 인텐트 필터는 앱의 매니페스트에 있는 <intent-filter> 요소에서 정의한다.
- 암시적 인텐트를 수신하기 위해서는 CATEGORY_DEFAULT 카테고리를 인텐트 필터에 포함해야 한다!
위의 코드는 앱의 진입점(=첫 시작)에 해당하는 Activity를 나타내는 인텐트 필터이다!
인텐트 필터의 하위 요소
- action : 수행할 액션 이름
- ACTION_MAIN : 시작엑티비티 지정 위한 액션 **
- ACTION_VIEW : 데이터의 URL로 가장 적절한 액티비티를 호출하는 액션 **
- ACTION_SEND : 다른 앱을 통해 사용자가 공유할 수 있는 일부 데이터가 있는 경우 사용하게 함 **
- ACTION_DEFAULT : ACTION_VIEW와 동일
- ACTION_DIAL : 전화 다이얼 액티비티를 호출하는 액션
- ACTION_WEB_SEARCH : 웹 검색 액티비티를 호출하는 액션
- data : 수행할 데이터의 URI
- category : 수행할 액션에 대한 추가적인 정보
- type : 수행할 인텐트 데이터의 명시적인 타입
예시를 통해 더 자세하게 알아보자면
<activity
android:name=".presentation.ExampleActivity"
android:exported="true"
android:label="@string/title_activity_example"
android:theme="@style/Theme.Assorted">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
A앱의 ExampleActivity에서 다음과 같이 Intent Filter를 작성한 상태라면
B앱에서 아래 코드로 intent 객체를 만든 뒤 StartActivity로 요청을 하게 되면,
val intent = Intent().apply {
action = Intent.ACTION_SEND
type = "text/plain"
putExtra(Intent.EXTRA_TEXT, "인텐트필터 연습")
}
startActivity(intent)
시스템이 사용자가 설치한 앱들을 모두 살펴보고 이 인텐트를 처리할 수 있는 앱이 어떤 것인지 알아 보게 된다. 그뒤 작성한 코드에 따라 사용자가 선택할 수 있고, 개발자가 강제로 앱을 지정할 수 있다고 한다.
Intent를 통한 데이터 전송의 크기 제한
안드로이드에서 Intent를 통해 데이터를 전달할 때, 실제로 Binder라는 IPC 메커니즘을 사용한다고 한다. 컴포넌트 간에 인텐트 전달을 위해 시스템을 거칠 시, 전달되는 argument나 값들은 Binder Transaction Buffer를 거치게 되는데, 이 버퍼의 크기는 1mb로 제한되어 있다.
문제는, 이 버퍼가 현재 수행중인 모든 트랜잭션이 공유해 사용하기 때문에 구글링시 대략 500KB 정도 전달할 수 있다(?) 암튼 대용량 데이터는 전달하기 힘들다고 한다. 제한을 초과했을 때에는TransactionTooLargeException이 발생하며, 어플리케이션이 비정상 종료될 수 있다.
Intent로 전달하지 않고 처리하는 방법?
1. 데이터 참조 전달
데이터 자체가 아닌, 데이터의 위치나 참조를 전달한다.
예를 들면, 파일 경로, URI, 데이터베이스 ID 등을 사용할 수 있다.
// 데이터 저장 (예: 파일 또는 데이터베이스에 저장)
fun saveLargeDataToFile(largeData: String): String {
val file = File(context.filesDir, "largeData.json")
file.writeText(largeData)
return file.absolutePath
}
// Intent에 데이터의 경로를 전달
val largeDataPath = saveLargeDataToFile(largeData)
val intent = Intent(this, TargetActivity::class.java).apply {
putExtra("DATA_PATH", largeDataPath)
}
startActivity(intent)
// TargetActivity에서 데이터 읽기
val dataPath = intent.getStringExtra("DATA_PATH")
val largeData = File(dataPath).readText()
2. Singleton 패턴 활용
애플리케이션 전체에서 접근 가능한 싱글톤 객체나 Application 클래스를 활용해 데이터를 저장하고 접근하도록 한다.
3. ContentProvider 사용
애플리케이션 간 또는 내부에서 데이터를 공유할 때 ContentProvider를 사용할 수 있다.
4. 파일 또는 데이터베이스 활용
큰 데이터를 파일 시스템이나 로컬 데이터베이스에 저장한 뒤, 해당 위치를 Intent로 전달하는 방법이다.
// 데이터 파일에 저장
fun saveLargeDataToFile(largeData: String): String {
val file = File(filesDir, "largeData.json")
file.writeText(largeData)
return file.absolutePath
}
// Intent에 파일 경로 전달
val filePath = saveLargeDataToFile(largeData)
val intent = Intent(this, TargetActivity::class.java).apply {
putExtra("FILE_PATH", filePath)
}
startActivity(intent)
// TargetActivity에서 파일 읽기
val filePath = intent.getStringExtra("FILE_PATH")
val largeData = File(filePath!!).readText()
이렇게 정리해본 결과 위의 질문에 어느 정도 대답 할 수 있을 것 같다.
1. 인텐트란 무엇인가요? → 컴포넌트를 실행하거나 컴포넌트들 사이에 데이터를 주고 받기 위한 메시징 객체 입니다
2. 인텐트의 종류가 무엇인가요? → 명시적 인텐트와 암시적 인텐트가 있습니다
3. 그럼 명시적 인텐트와 암시적인텐트의 차이는 뭐고 언제 쓰이나요?
→ 명시적 인텐트는 같은 앱내 컴포넌트의 명을 직접 지정하여 컴포넌트를 실행하는 것이고, 암시적 인텐트의 경우 외부 컴포넌트를 실행시키는데 사용 하며 action, category, data를 지정한 intent 객체를 생성해 시스템에 전달하고 시스템이 위의 작성한 형식과 맞는 컴포넌트를 찾아 실행시켜주는 것입니다!
4. Intent의 데이터 전달 크기 제한이 있나요?
-> 넵 대략 Intent는 Binder Transaction Buffer를 거치게 되는데 이 버퍼의 크기는 1MB입니다. 그래서 용량이 큰 데이터를 전달할 때 앱이 크래쉬가 발생할 수 있습니다!
-> 이를 해결하려면, 싱글톤 패턴을 사용하거나 Content Provider 또는 파일, 데이터 베이스를 활용해 로컬에 저장한뒤 데이터가 저장된 위치를 전달해주는 방법을 사용할 수 있습니다.
pendingIntent에 대한 내용은 따로 작성!
'Android > Android' 카테고리의 다른 글
[Android] Gradle (0) | 2024.07.15 |
---|---|
[Android] Jetpack이란? (0) | 2024.07.09 |
[Android] Hilt 정리 (0) | 2024.06.16 |
[Android] DI - Hilt vs koin 비교 (1) (2) | 2024.05.09 |
[Android] 안드로이드 스레드 (0) | 2023.12.19 |