안드로이드/Kotlin

[안드로이드][Kotlin] 액티비티 간의 데이터 전달 (+registerForActivityResult() 사용)

sinw212 2023. 8. 1. 21:31

안드로이드 개발을 하다보면, Activity 간의 데이터를 전달하는 상황이 발생한다.

 

먼저 단방향으로 데이터를 전달하는 방법에 대해 알아보자.

다른 Activity로 데이터를 전달하기 위해서는 다른 앱 구성요소로 작업을 요청하는 일종의 메시지 객체인 intent 객체에 데이터를 담아 전달할 수 있다.

다른 Activity 로 데이터를 전달할 때는 일반적으로 명시적 인텐트를 사용한다.

 

(참고) 명시적 인텐트 VS 암시적 인텐트

더보기

- 명시적 인텐트(Explicit Intent)

시작할 구성요소 이름을 Intent 객체에 설정하여 넘기는 방식으로, 일반적으로 현재 앱 안의 구성요소를 시작시킬 때 사용한다.

startActivity(Intent(this, SubActivity::class.java))

- 암시적 인텐트(Implicit Intent)

시작할 구성요소 이름을 지정하지 않고 일반작업을 Intent 객체에 설정하여 넘기는 방식으로, 일반적으로 다른 앱 안에 있는 구성요소를 구동할 때 사용한다. (ex. 전화걸기, 지도보기 등)

모든 앱을 검색하여 해당 인텐트와 일치하는 인텐트 필터를 찾고, 일치된 인텐트 필터를 포함한 앱 구성 요소를 시작시킨다. (ex. 웹 브라우저를 열고싶은데, 웹 브라우저를 사용하는 앱에는 네이버, 크롬 등등 여러개가 있는 상황이기 때문에 그 중 하나를 선택)

startActivity(Intent(Intent.ACTION_DIAL, Uri.parse("tel:114")))

 

아래 예시는 MainActivity의 button을 클릭했을 때 intent 객체에 "cat"라는 데이터를 담아 SubActivity로 전달하는 코드이다.

/* MainActivity.kt */
...
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        button.setOnClickListener { //버튼 클릭 리스너
            val mainIntent = Intent(this, SubActivity::class.java)
            mainIntent.putExtra("animal", "cat")
            startActivity(mainIntent)
        }
    }
}
/* SubActivity.kt */
...
class SubActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        val animal = intent.getStringExtra("animal") //cat 반환
    }
}

 

위와 같이 단방향으로 데이터를 전달하는 것이 아닌, 쌍방향으로 데이터를 전달해야 하는 상황이 있다.

 

쌍방향으로 데이터를 전달하는 방법으로 기존에 사용하던 startActivityForResult() 가 deprecated 된 후, registerForActivityResult() 를 사용한다.

 

먼저 deprecated 된 startActivityForResult() 에 대해 알 필요가 있다.

startActivityForResult 메소드를 사용하려면 onActivityResult 에서 콜백을 처리해줘야한다. 이 방법에는, 결과를 얻는 Activity를 실행하는 로직을 사용할 때 메모리 부족으로 인해 프로세스와 Activity가 사라질 수 있다는 문제점이 존재한다. (특히 카메라와 같은 메모리 사용량이 많은 작업은 소멸될 확률이 굉장히 높다.)

이 문제점에 대한 대안으로 registerForActivityResult 메소드가 사용된다.

 

Activity가 종료되고 다시 만들어질 때 Activity에게 Result를 기다리는 상황이라고 알려줘야하기 때문에 Activity를 실행하는 부분과 Result Callback 부분을 분리해줘야 할 필요가 있다.

그 역할을 해주는 것이 ActivityResultLauncher 객체이며, Result Callback 부분을 분리해서 구현하기 때문에 기존에 사용하던 requestCode가 더이상 필요하지 않다.

 

즉, ActivityResultLuancher 객체와 registerForActivityResult 메소드를 사용하면, Activity가 종료되었다가 다시 만들어지더라도 Result 값을 기다리고 있음을 알려줄 수 있다.

 

위 설명에 대한 예시로는 아래와 같다.

더보기

- startActivityResult 메소드와 onActivityResult 메소드를 사용한 경우 (deprecated 됨)

    1. A Activity -> B Activity 실행 후, 메모리가 부족하며 A Activity가 소멸됨

    2. B Activity 종료 후,  setResult() 메소드로 결과값을 넘김

    3. A Activity가 소멸되었다가 다시 생성되었기 때문에 B Acticity에서 결과값이 넘어온 것을 모르는 상황

- ActivityResultLauncher 객체와 registerForActivityResult 메소드를 사용한 경우 (본 게시물에서 다루는 내용)

    1. A Activity -> B Activity 실행 후, 메모리가 부족하여 A Activity가 소멸됨

    2. B Activity 종료 후, setResult() 메소드로 결과값을 넘김

    3. A Activity가 소멸되었다가 다시 생성되어도 registerForActivityResult() 메소드가 다시 콜백을 등록해줘서 결과값을 받아올 수 있음

 

아래 코드는 registerForActivityResult()를 활용하여, MainActivity에서 button을 클릭하여 SubActivity로 이동 후 SubActivity에서 button을 클릭하여 MainActivity로 돌아올 때 "Maltese" 라는 데이터를 받아오는 코드이다.

/* MainActivity.kt */
...
class MainActivity : AppCompatActivity() {
    lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
    
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        activityResultLauncher = registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()) {
            if(it.resultCode == RESULT_OK) {
                val dogType = it.data?.getStringExtra("dogType") //Maltese 반환
            }
        }
        
        button.setOnClickListener { //버튼 클릭 리스너
            val mainIntent = Intent(this, SubActivity::class.java)
            activityResultLauncher.launch(mainIntent)
        }
    }
}
/* SubActivity.kt */
...
class SubActivity : AppCompatActivity() {
    ...
    button.setOnClickListener {
        val subIntent = Intent(this, MainActivity::class.java).apply {
            putExtra("dogType", "Maltese")
        }
        setResult(RESULT_OK, subIntent)
        if(!isFinishing) {
            finish()
        }
    }
}

 

참고사이트

 

활동에서 결과 가져오기  |  Android 개발자  |  Android Developers

활동에서 결과 가져오기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 앱 내에서든 다른 앱에서든 다른 활동을 시작하는 것은 단방향 작업이 아니어도 됩

developer.android.com