ANDROID/Android 개발 이슈 & 해결

[Android] startActivityForResult() deprecated 해결 : Activity Result API

주 녕 2021. 7. 29. 17:50
반응형

안드로이드 인스타그램 클론 프로젝트를 진행하던 중에 새로운 문제를 만났다.

오랜만에 안드로이드 스튜디오와 코틀린을 최신 버전으로 업데이트 받았는데, startActivityForResult() 메소드가 deprecated 되어있었다. 찾아보니 2020년 5월에 이미 deprecated 되었다고 한다 😓😓

 

startActivityForResult()가 deprecated된 이유

  1. AndroidX Activity, Fragment에 도입된 Activity Result API 사용을 적극 권장하고 있음
  2. 결과를 얻는 Activity를 실행하는 로직을 사용할 때, 메모리 부족으로 인해 프로세스와 Activity가 사라질 수 있음

기존 방법은 Activity에서는 startActivityResult를 통해서 콜백을 등록하고, onActivityResult에서 콜백을 처리한다.

두 메서드가 같은 곳에서 구현을 해야하는데, 메모리 부족으로 제대로 동작을 안할 수 있다는 것이다.

→ Activity가 종료되었다가 다시 생성되었을 때 Activity에게 결과를 기다리는 중임을 다시 알려야 한다.

 

기존 API

화면 전환

  • startActivity(Intent intent) : 새로운 Activity 시작 (단방향)
  • startActivityForResult(Intent intent, int requestCode, Bundle options) : 새로운 Activity 시작 + 결과값 전달 (쌍방향)

startActivityForeResult는 startActivity와 다르게 requestCode를 이용하여 어떤 Activity인지 식별할 수 있다.

 

결과 반환 및 전달

  • setResult(int resultCode)
    • Activity가 종료되면 해당 메서드를 통하여 데이터를 상위 항목으로 되돌릴 수 있음
    • 새롭게 시작한 Activity의 종료시점에 호출하여 데이터를 상위(parent)로 보내고 resultCode를 전달해야 함
    • resultCode : RESULT_OK, RESULT_CANCELED(충돌 등으로 실패하는 경우), 사용자 지정
    • 이 모든 정보는 상위(parent)의 Activity.onActivityResult()에 다시 나타남
  • onActivityResult(int requestCode, int resultCode, Intent data) : 실행한 Activity가 종료되어 시작한 requestCode, 반환된 resultCode, 추가 데이터를 제공할 때 호출

 

새로운 API

Activity Result API는 다른 Activity를 실행하는 코드에서 결과 콜백을 분리한다.
Result Callback은 프로세스와 Activity를 다시 생성할 때 사용할 수 있어야 하므로 다른 Activity를 실행하는 로직이 사용자 입력 또는 기타 비즈니스 로직을 기반으로 발생하더라도 Activity가 생성될 때마다 콜백을 무조건 등록해아 한다.

위의 기존 방법이 deprecated된 이유를 설명하면서 왜 Activity와 Result Callback을 분리해야 하는지 설명했다.

registerForActivityResult()는 ActivityResultContract 및 ActivityResultCallback을 가져와서 다른 Activity를 실행하는데 사용할 ActivityResultLauncher를 반환함

registerForActivityResult() 메서드는 함수명에서 알 수 있듯이, 콜백을 등록하는 역할을 한다.

따라서 ActivityResultLauncher와 registerForActivityResult() 메서드를 사용하면 Activity가 종료되었다가 다시 생성되어도 결과를 기다리고 있다는 것을 알려줄 수 있는 것이다.

 

🤔 새로운 API에서 requestCode가 없는 이유?

원하는 Activity Request마다 registerForActivityResult를 실행하여 Result Callback을 분리해서 구현하므로

Activity를 구분할 필요가 없어졌기 때문이다!

 

private lateinit var getResult: ActivityResultLauncher<Intent>

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ...
    
    // 결과를 받기 위한 Callback 등록
    getResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
        if (it.resultCode == RESULT_OK) {
            ...
        }
    }
    ...
    
    binding.btn.setOnclickListener {
        val intent = Intent(...)
        getResult.launch(intent)
    }
}
  • 람다식의 it은 결과를 나타낸다. (result 등으로 인자를 명시하고 사용해도 무관)
  • it.resultCode, it.data 등으로 결과 코드(resultCode)와 데이터(Intent)에 접근할 수 있음
  • launch() 함수로 시작함

함수의 인자로 들어가는 함수는 ActivityResultContracts 클래스의 static 함수로,

결과를 받기 위해 Activity를 실행하는 StartActivityForResult() 함수를 인자로 넣는다.

 

launch()를 통해 이동한 새로운 Activity에서는 기존과 동일하게 setResult() 함수를 그대로 사용하면 된다!

→ resultCode와 Intent 데이터를 인자로 가지는 함수

 

 

 

 

 

실제 예시에서 적용한 포스팅은 아래를 참고!

 

[Android] Activity Result API : Fragment에서 registerForActivityResult()

2019년 클론 프로젝트 강의를 보면서 진행하다보니 deprecated를 정말 많이 마주치는 것 같다. 오늘은 지난 포스팅에 이어 Fragment에서 Activity Result API를 사용하는 방법에 대해 포스팅한다! 우선 하고

junyoung-developer.tistory.com


reference>

반응형