안드로이드

[Android | Kotlin] 인텐트 이해하기

jay20033 2023. 12. 25. 16:10

액티비티 컴포넌트는 화면을 구성하는 컴포넌트이며, 앱의 화면을 안드로이드폰에 출력하려면 액티비티 컴포넌트를 만들어야 하며, 앱이 실행되면 액티비티에서 출력된 내용이 안드로이드폰에 나옵니다.

 

인텐트란?

  • '컴포넌트를 실행하려고 시스템에 전달하는 메시지'
  • 컴포넌트 클래스는 개발자가 코드에서 직접 생성해서 실행할 수 없습니다.
  • 시스템에서 인텐트의 정보를 분석해서 그에 맞는 컴포넌트를 실행해 줍니다.
  • 외부 앱의 컴포넌트와 연동할 때도 마찬가지입니다.

기본적으로 한 MainActivity가 실행되고 나서 DetailActivity로 화면을 전환한다면 객체를 생성해서 실행하면 될 것 같지만, DetailActivity가 component class라면 시스템이 생성해서 실행하는 클래스이므로 개발자가 작성하는 코드로 생명주기를 관리할 수 없습니다. 이때, 시스템에 Intent를 전달해 주게 되면 시스템에서 Intent의 정보를 분석해서 그에 맞는 컴포넌트를 실행하게 됩니다.

 

매니페스트 파일에 컴포넌트를 등록해 시스템에 컴포넌트를 알려주어야 합니다.

시스템은 런타임 때 매티페스트 파일의 정보를 참조하여 앱을 실행하기 때문에 매니패스트 파일에 컴포넌트를 등록해 놓지 않으면 시스템은 해당 컴포넌트를 알 수 없어 해당 컴포넌트를 실행할 수 없습니다.

<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>
<activity 
    android:name=".DetailActivity"
    android:exported="true">
</activity>

 

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

MainActivity에서 DetailActivity를 실행하고자 인텐트를 시스템에 전달하는 코드입니다.

결국, DetailActivity를 실행해 달라는 정보를 Intent 객체에 대입한 것입니다.

 

엑스트라 데이터란?

엑스트라 데이터는 '인텐트에 담는 부가 정보'라 할 수 있습니다.

인텐트를 이용해 데이터를 전달해야 할 때, 컴포넌트 객체는 시스템이 생성하므로 직접 접근할 수 없기에 엑스트라 데이터를 이용해야 합니다.

 

val intent: Intent = Intent(this, DetailActivity::class.java)
intent.putExtra("data1", "hello")
intent.putExtra("data2", 123)
startActivty(intent)

putExtra( ) 함수를 이용하여 MainActivity에 엑스트르 데이터를 추가해서 전달합니다.

첫 번째 매개변수는 데이터의 식별자이며 두 번째 매개변수는 전달할 데이터입니다.

 

val data1 = intent.getStringExtra("data1")
val data2 = intent.getIntExtra("data2", 0) // 0은 defaultValue

반대로 인텐트로 실행된 컴포넌트에서 엑스트라 데이터를 가져오려면

getIntExtra( ), getStringExtra( ), getDoubleExtra( )... 를 사용합니다.

 

액티비티 화면 되돌리기

화면을 전환했다가 다시 돌아왔을 때 사후 처리를 해야 할 수도 있습니다.

인텐트로 액티비티를 시작하는 방법은 3가지

  • public void startActivity(Intent intent)
  • public void startActivityForResult(Intent intent, int requestCode) // requestCode는 intent를 식별하는 값
  • ActivityResultLauncher

사후 처리가 필요 없을 때는 startActivity( )함수를 사용

사후 처리가 필요할 때는 startActivityForResult( ) or ActivityResultLauncher를 사용

♬ 안드로이드 11 버전이 나올 즈음부터는 androidx의 ActivityResultLauncher를 권장

 

액티비티 화면 되돌리기 - startActivityForResult( )

intent.putExtra("resultData", "world")
setResult(RESULT_OK, intent)
finish()

화면을 되돌릴 때는 finish( )함수를 사용하며 현재 화면에 보이는 액티비트를 종료해 달라고 시스템에 요청

setResult( ) 함수는 결과를 어떻게 되돌릴지 지정

RESULT_OK or RESULT_CANCLED 등 상수를 지정

 

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == 10 && resultCode == Activity.RESULT_OK) {
        val result = data?.getStringExtra("resultData")
    }
}
  • 결과가 되돌아와서 다시 자신이 화면에 출력되면 onActivityResult( ) 함수가 자동으로 호출
  • resultCode: 인텐트를 시작한 곳에서 인텐트를 구분하려고 설정한 요청 코드
  • resultCode: 인텐트로 실행된 곳에서 돌려받은 결과 코드
  • data: 인턴트 객체이며 이 객체에 결과 데이터가 있습니다.

결과를 되돌려 받는 코드의 구조

 

액티비티 화면 되돌리기 - ActivityResultLauncher

ActivityResultLauncher는 액티비티에서 다양한 결과에 대한 사후 처리를 제공

ActivityResultLauncher를 이용하려면 Contract 객체가 필요합니다.

Contract는 ActivityResultLauncher로 실행될 요청을 처리하는 역할을 합니다.

☞ ActivityResultLauncher로 인텐트를 발생시켜 액티비티를 실행할 때 실제 인텐트를 발생시키는 역할을 합니다.

 

Contract

  • PickContact: 선택한 연락처의 Uri 획득
  • RequestPermission: 권한 요청, 허락 여부 파악
  • RequestMultiplePermissions: 여러 권한을 동시에 요청
  • StartActivityForResult: 인텐트 발생, 액티비티 실행 결과 획득
  • TakePicturePreview: 사진 촬영 후 비트맵 획득
  • TakePicture: 사진 촬영, 저장, 비트맵 획득
val requestLauncher: ActivityResultLauncher<Intent> = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult())
{
    val resultData = it.data?.getStringExtra("result")
    binding.mainResultView.text = "result : $resultData"
}

ActivityResultLauncher는 registerForActivityResult( ) 함수로 만드는 객체이며 매개변수에 Contract 객체와 결과를 처리하는 Callback 객체를 등록해야 합니다.

 

val intent: Intent = Intent(this, DetailActivity::class.java)
requestLauncher.launch(intent)

launch 함수를 호출하는 순간 ActivityResultLauncher에 등록된 Contract 객체가 실행됩니다.

 

인텐트 필터

인텐트는 실행할 컴포넌트를 어떻게 설정하는지에 따라 2가지로 나뉩니다.

  • 명시적 인텐트: 클래스 타입 레퍼런스 정보를 활용한 인텐트
  • 암시적 인텐트: 인텐트 정보를 활용한 인텐트

♬ 클래스 타입 레퍼런스를 이용하는 것을 명시적 인텐트

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

♬ 외부 앱의 컴포넌트는 클래스 타입 레버런스를 활용할 수 없으므로 암시적 인텐트를 이용

암시적 인텐트는 매니페스트 파일에 선언된 인텐트 필터를 이용

<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>

앱 내부에서만 이용되는 컴포넌트라면 android:name 속성만 선언하면 됩니다.

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

 

<intent-filter> 하위에는 <action>, <category>, <data> 태그를 이용해 정보를 설정

어떤 정보를 설정할 것인지는 개발자의 선택

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

액티비티 인텐트 동작 방식

  • 없을 때: 인텐트를 시작한 곳에 오류가 발생 (예외 처리를 해줘야 함)
  • 1개일 때: 문제없이 실행
  • n개일 때: 사용자 선택으로 하나만 실행 (사용자가 선택하는 대로 하나만 실행됨)

만약 액티비티가 여러 개 있더라도 사용자에게 묻지 않고 특정 앱의 액티비티를 실행하고 싶은 경우

해당 앱의 패기지명을 지정하면 됩니다.

setPackage( ) 함수로 실행할 앱의 패기지를 지정합니다.

val intent = Intent(Intent.ACTION_VIEW, Uri.parse("geo:37.7749,127.4194"))
intent.setPackage("com.google.android.apps.maps")
startActivity(intent)