1. 액티비티 간 양방향 데이터 전달 (Activity Result API)
- Activity Result API를 이용하여 액티비티 간 양방향 데이터 전달을 구현함.
- 실행 흐름은 크게 Part 1 (SecondActivity 실행)과 Part 2 (데이터 회신)로 구성됨.
Part 1: ActivityResultLauncher 실행 (MainActivity)

- 1. ActivityResultLauncher 객체 생성 (호출 측)
- <MainActivity>에서 registerForActivityResult()를 이용해 ActivityResultLauncher 객체를 생성하고 초기화.
- 이때 실제 작업자인 Contract 객체와, 결과 수신 시 호출될 콜백(callback) 메소드를 등록.
val requestLauncher: ActivityResultLauncher<Intent> = registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { /* * SecondActivity에서 결과를 받았을 때 호출될 콜백 함수 구현 * (예: it.resultCode, it.data 등을 확인) */ }
- 2. ActivityResultLauncher 실행 (호출)
- 호출할 대상 액티비티(예: SecondActivity)를 명시한 인텐트(Intent)를 생성.
- (필요시) intent.putExtra()를 사용해 데이터 추가.
- activityResultLauncher.launch(intent) 메소드를 호출하여 인텐트를 실행.
val intent: Intent = Intent(applicationContext, SecondActivity::class.java) // intent.putExtra(...) // 필요시 데이터 추가 requestLauncher.launch(intent)
- 3. 데이터 수신 (피호출측)
- <SecondActivity>(피호출측)는 getIntent()를 통해 인텐트를 수신.
- getExtra() 등을 사용해 <MainActivity>가 전달한 데이터를 추출.
Part 2: 데이터 회신 (SecondActivity)

- 4. 결과 인텐트 생성 (피호출측)
- <SecondActivity>는 <MainActivity>로 회신할 txIntent (전송용 인텐트)를 생성.
- txIntent.putExtra()를 사용해 반환할 데이터를 추가.
- 5. 결과 설정 및 액티비티 종료 (피호출측)
- setResult(<result-code>, txIntent) 메소드를 호출하여 결과 코드(예: RESULT_OK)와 데이터(txIntent)를 설정.
- (이후 finish()가 호출되면 액티비티가 종료되고 결과가 전달됨)
- 6. 결과 수신 (호출측)
- <MainActivity>에서 ActivityResultLauncher 생성 시 등록했던 콜백 메소드가 실행됨.
- 콜백 메소드는 <result-code>와 데이터를 포함한 ActivityResult 객체를 파라미터로 받음.
2. 실습 : 양방향 데이터 전달 (덧셈 + 뺄셈)
- Activity Result API를 이용해 MainActivity와 AddActivity로 구성된 양방향 데이터 전달 앱 구현.
- 실행 흐름:
- MainActivity에서 숫자 2개(예: 10, 20)를 입력하고 'ADD' 버튼 클릭.
- AddActivity가 실행됨.
- AddActivity는 'RESPOND THE SUM' 버튼을 눌러 합계(예: 30)를 MainActivity로 회신.
- MainActivity는 콜백을 통해 결과를 받아 "Sum: 30"을 화면에 출력.
- 확장:
- 기존 덧셈 앱에 뺄셈 연산을 위한 SubActivity를 추가.
- MainActivity는 '더하기' 버튼과 '빼기' 버튼을 가짐.
- MainActivity는 result-code를 통해 결과를 반환한 액티비티를 구분.
- AddActivity 는 setResult()로 <result-code> = 1001을 반환.
- SubActivity 는 setResult()로 <result-code> = 1002를 반환.


// MainActivity.kt
package com.cookandroid.activityexcercise2
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import com.cookandroid.activityexcercise2.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var bindingMain : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// enableEdgeToEdge()
// setContentView(R.layout.activity_main)
// ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
// val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
// v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
// insets
// }
bindingMain = ActivityMainBinding.inflate(layoutInflater)
setContentView(bindingMain.root)
val requestLauncher : ActivityResultLauncher<Intent> = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()){
// AddActivity로부터 결과를 수신 받으면 호출할 callback 함수
if(it.resultCode == 1001) { // resultCode를 AddActivity로부터 확인
val responseIntent : Intent? = it.data
val sum : Int? = responseIntent?.getIntExtra("Sum", 0)
Toast.makeText(this, "Sum = " + sum?.toString(), Toast.LENGTH_LONG).show()
}
if(it.resultCode == 1002) { // resultCode를 SubActivity로부터 확인
val responseIntent : Intent? = it.data
val sub : Int? = responseIntent?.getIntExtra("Sub", 0)
Toast.makeText(this, "Sub = " + sub?.toString(), Toast.LENGTH_LONG).show()
}
}
bindingMain.btnAdd.setOnClickListener(object : View.OnClickListener {
override fun onClick(p0: View?){
val mIntent : Intent = Intent(applicationContext, AddActivity::class.java)
mIntent.putExtra("Num1", Integer.parseInt(bindingMain.edtNum1.text.toString()))
mIntent.putExtra("Num2", Integer.parseInt(bindingMain.edtNum2.text.toString()))
requestLauncher.launch(mIntent)
}
})
bindingMain.btnSub.setOnClickListener(object : View.OnClickListener {
override fun onClick(p0: View?){
val mIntent : Intent = Intent(applicationContext, SubActivity::class.java)
mIntent.putExtra("Num1", Integer.parseInt(bindingMain.edtNum1.text.toString()))
mIntent.putExtra("Num2", Integer.parseInt(bindingMain.edtNum2.text.toString()))
requestLauncher.launch(mIntent)
}
})
}
}
// AddActivity.kt
package com.cookandroid.activityexcercise2
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.cookandroid.activityexcercise2.databinding.ActivityAddBinding
class AddActivity : AppCompatActivity() {
private lateinit var bindingAdd : ActivityAddBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bindingAdd = ActivityAddBinding.inflate(layoutInflater)
setContentView(bindingAdd.root)
val rxIntent : Intent = getIntent()
val rxNum1 : Int = rxIntent.getIntExtra("Num1", 0)
val rxNum2 : Int = rxIntent.getIntExtra("Num2", 0)
val sum : Int = rxNum1 + rxNum2
// AddActivity를 종료시켜서 자동으로 MainActivity로 돌아감
bindingAdd.btnReturn.setOnClickListener(object: View.OnClickListener {
override fun onClick(p0: View?){
val responseIntent : Intent = Intent(applicationContext, MainActivity::class.java)
responseIntent.putExtra("Sum", sum)
setResult(1001,responseIntent) // setResult(<result code>, txIntent)
finish()
}
})
}
}
// SubActivity.kt
package com.cookandroid.activityexcercise2
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.cookandroid.activityexcercise2.databinding.ActivitySubBinding
class SubActivity : AppCompatActivity() {
private lateinit var bindingSub : ActivitySubBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bindingSub = ActivitySubBinding.inflate(layoutInflater)
setContentView(bindingSub.root)
val rxIntent : Intent = getIntent()
val rxNum1 : Int = rxIntent.getIntExtra("Num1", 0)
val rxNum2 : Int = rxIntent.getIntExtra("Num2", 0)
val sub : Int = rxNum1 - rxNum2
// SubActivity를 종료시켜서 자동으로 MainActivity로 돌아감
bindingSub.btnReturn.setOnClickListener(object: View.OnClickListener {
override fun onClick(p0: View?){
val responseIntent : Intent = Intent(applicationContext, MainActivity::class.java)
responseIntent.putExtra("Sub", sub)
setResult(1002,responseIntent) // setResult(<result code>, txIntent)
finish()
}
})
}
}
// AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ActivityExcercise2">
<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=".AddActivity"
android:exported="true"/>
<activity android:name=".SubActivity"
android:exported="true"/>
</application>
</manifest>
// activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal"
tools:context=".MainActivity">
<EditText
android:id="@+id/edtNum1"
android:hint="enter first number"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/edtNum2"
android:hint="enter second number"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btnAdd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add"/>
<Button
android:id="@+id/btnSub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sub"/>
</LinearLayout>
// activity_add.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="@android:color/holo_blue_bright"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btnReturn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="RESPOND THE SUM"/>
</LinearLayout>
// activity_sub.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:background="@android:color/holo_green_light"
android:layout_height="match_parent">
<Button
android:id="@+id/btnReturn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="RESPOND THE SUB"/>
</LinearLayout>'MOBILE PROGRAMING' 카테고리의 다른 글
| [모바일 프로그래밍] Fragment와 생명 주기 + 실습 (0) | 2025.11.05 |
|---|---|
| [모바일 프로그래밍] 암시적 Intent와 액티비티 생명 주기 (0) | 2025.11.03 |
| [모바일 프로그래밍] Activity와 Intent(단방향) (0) | 2025.10.23 |
| [모바일 프로그래밍] 토스트(Toast)와 대화 상자(AlertDialog) (0) | 2025.10.20 |
| [모바일 프로그래밍] 메뉴 (Option Menu & Context Menu) (0) | 2025.10.13 |