안드로이드

Activity Result API 학습

란서 2023. 3. 29. 11:28

 Activity Result API 개요

안드로이드를 사용하다보면 다른 앱의 구성요소(활동)으로 데이터를 요청하여 받아와야 하는 경우가 생긴다.


이때 startActivityForReseult(Intent) 를 사용하여 다른 활동으로부터 결과를 받아오고
onActivityResult(...) 를 재정의하여 받아온 결과에 대해 어떻게 사용할 지 코드를 구현할 수 있다.

그런데 최근 최신 버전의 android 에서는 startActivityForResult() 와 onAcitvityResult() 를 사용하는 것 대신 
AndroidX Activity와 Fragment에 도입된 Activity Result API 를 사용하는 것을 적극 권장하고 있다.


Activity Result API 사용

activity result api는 시스템에서 결과가 전달되면 
이를 등록, 실행, 처리 하기 위한 구성요소를 제공한다.

 

 

1. 등록

Activity Result API를 사용하기 위해서는 'ActivityResultLauncher' 객체를 등록해야 한다.

ActivityResultLauncher 객체를 생성하려면 'registerForActivityResult()' 메서드를 사용해야 한다.

registerForActivityResult() 메서드는 Activity 또는 Fragment에서 사용할 수 있는 메서드이다.
해당 메서드는 두 가지 매개변수를 갖는다.

매개변수
1. contracts : ActivityResultContracts 
2. callback : ActivityResultCallback 

소스코드

val someActivityResultLauncher = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            val data: Intent? = result.data
            // 결과 데이터 처리
        }
    }

위의 예시에서 registerForActivityResult() 메서드를 사용하여 ActivityResultLauncher 객체를 생성하고 있음

매개변수
1.contract 의 자리에는 ActivityResultContracts.StartActivityForResult() 라는 ActivityResultContracts의
인스턴스를 넘겨주고 있다.

(*ActivityResultContracts.StartActivityForResult() = 다른 Acitivity를 실행하고 결과 값을 받기 위한 객체) 


2.callback 의 자리에는 ActivityResultCallback 인터페이스람다식으로 구현하여 인자로 넘겨주고 있다.
(시스템에서 받아온 result(결과값)을 통해 어떤 액션을 취할 것인지 코드로 구현할 수 있다.)

 

2.실행

1.Activity Result API를 사용하기 위한 등록의 과정 (=AcitivityResultLauncher 객체 생성)을 마치고 나면
이제 실제로 다른 Activity를 실행하여 결과값을 받아와야 할 것이다.

 

이 때 ActivityResultLauncher 객체를 사용할 수 있다. ActivityResultLauncher.launch() 메서드를 호출하여 다른

Activity를 실행한다.

소스코드

someActivityResultLauncher.launch(Intent(this, AnotherActivity::class.java))

 

3.처리

2.다른 Activity 실행하고 결과값을 받아왔다면 전달된 결과값을 처리해야 할 것이다.

처리과정은 이미 1.등록의 과정에서 거의 완성을 해두었다.

바로 ActivityResultLauncher 객체를 만들기 위해 registerForActivityResult() 메서드를 사용할 때,

두 번째 매개변수 2.callback 으로 넘겨준 ActivityResultCallback 인터페이스 구현 객체가 바로 처리 과정의 핵심이다.

val someActivityResultLauncher = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            val data: Intent? = result.data
            // 결과 데이터 처리
        }
    }

해당 람다식에서 result 를 이용하여 전달받은 결과 데이터를 처리해주는 코드를 구현 해주면된다.

 


ActivityResultContracts

registerForActivityResult() 메서드를 호출할 때 첫번째 매개변수의 타입인 ActivityResultContrancts 클래스는
Activitiy Result API에서 제공하는 다양한 인텐트 작업에 대한 계약(Contract)를 나타낸다. 
이 클래스의 인스턴스를 사용하여 Activity Result API에서 지원하는 다양한 종류의 결과 값(ex. 이미지 선택, 파일 선택 등)을 처리할 수 있습니다.

종류

  • ActivityResultContracts.StartActivityForResult : 다른 Activity를 시작하고 결과값을 받는 계약을 의미.
  • ActivityResultContracts.RequestPermission : 퍼미선 요청 결과 (권한) 를 받는 계약을 의미.
  • ActivityResultContracts.TakePicture : 카메라로 사진을 찍어 결과를 받는 계약을 의미.
  • ActivityResultContracts.OpenDocument : 문서를 열어 결과를 받는 계약을 의미.
  • ActivityResultContracts.GetContent : 파일을 선택하여 결과를 받는 계약을 의미.

 

이외에도 다양한 종류의 결과 값을 처리할 수 있는 인스턴스 제공합니다.

소스 코드 (ex.ActivityResultContracts.TakePicture 를 사용하는 예시)

class MyActivity : AppCompatActivity() {

    private lateinit var myActivityResultLauncher: ActivityResultLauncher<Uri>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_my)

        // ActivityResultLauncher 객체 등록
        myActivityResultLauncher = registerForActivityResult(
            ActivityResultContracts.TakePicture()) { success: Boolean ->
            if (success) {
                // 사진 촬영 성공
            } else {
                // 사진 촬영 실패
            }
        }

        // 버튼 클릭 시 카메라 앱 실행
        myButton.setOnClickListener {
            myActivityResultLauncher.launch(createImageFileUri())
        }
    }

    // 임시 파일 경로 생성
    private fun createImageFileUri(): Uri {
        val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
        val storageDir: File? = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
        val file = File.createTempFile(
            "JPEG_${timeStamp}_",
            ".jpg",
            storageDir
        )
        return FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileprovider", file)
    }
}