AndroidX - ActivityResultContract

강성우, 24 June 2020

안드로이드 컴포넌트 중 하나인 Activity간의 데이터를 처리 하는 방법으로 startActivityForResult()onActivityResult() 콜백이 있다. 이 방식의 Activity result처리 방법을 개선한 ActivityResultContract에 대해서 간단하게 알아보려 한다.

ActivityResultContract API 패키지는 activity:1.2.0-alpha02, fragment:1.3.0-alpha02버전 부터 도입 되었으며, alpha04버전 부터는 startActivityForResult(), onActivityResult()메소드 들은 Deprecate 되었다.

ActivityResultContract는 이 글 작성시점에서 정식 릴리즈되지 않았기 때문에 사용은 추천되지 않으며 실제 이 글과 정식 릴리즈 버전과 차이가 있을 수 있다. 이 글에서는 ActivityResultContract에 대한 찍어먹기로 어떤 개념인지 가볍게 알아보려 한다.

1. startActivityForResult(), onActivityResult() 방법

이전 Activity간 결과 데이터를 핸들링 하기 위해서는 아래와 같은 방법으로 사용 되었다.

class SomeActivity: Activity() {
    fun onClickedNextButton() {
        val intent = Intent(context, MainActivity::class.java)
        activity.startActivityForResult(intent, REQUEST_CODE_MAIN_ACTIVITY)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_CODE_MAIN_ACTIVITY) {
            if (resultCode == Activity.RESULT_OK) {
                // ...
            } 
            else if (resultCode == Activity.RESULT_CANCELED) {
                // ...
            }
        }
    }
}

2. 새로운 API

androidX 에서 제공하는 API의 사용 예는 아래와 같다.

class SomeActivity: Activity() {
    val activityResultHandler: ActivityResultLauncher<Intent> = registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()
        ) { result ->
            // ... 
        }

    fun startMainActivity() {
        val intent = Intent(context, MainActivity::class.java)
        activityResultHandler(intent)
    }
}

새로운 API 에서는 ActivityResultLauncher을 사용 한다. 기존 방법과 동일하게 Intent를 사용 하지만 startActivityForResult()onActivityResult()을 사용 하지 않으며 멤버로 구현된 ActivityResultLauncher 을 이용 하여 ActivityResult를 핸들링 하는 람다가 있음을 확인할 수 있다. (참고로 Fragment에서의 사용법은 동일 하다.)

자세히 보면, registerForActivityResult()함수를 이용 해서 StartActivityForResult을 넘겨 ActivityResultActivityResultCallback인터페이스를 람다 구현의 블럭내로 전달 해 준다. ActivityResultCallback의 구현 내부는 이전 과 동일하긴 하지만 ActivityResult라는 데이터 클래스가 사용 된다.

public final class ActivityResult implements Parcelable {
    private final int mResultCode;
    @Nullable
    private final Intent mData;

    //...
}

기존 onActivityResult()에서 사용 되던 requestCode는 더이상 사용되지 않아 없어졌으며 resultCodeIntentdata는 그대로 임을 확인 할 수 있다. requestCode는 이전 result를 구분하기 위해 launch시점의 구분 플래그 역활을 했었지만 이제는 람다 함수로 구현되어 콜백을 받기 때문에 requestCode로 호출자를 구분할 필요가 없어져서 그런것 같다.

3. 결말

아직 알파버전에 안정된 정식 릴리즈버전이 아니어서 실제 사용에는 추천되지 않는다. 사용해본 바 에는 이전의 메소드 재정의를 통한 콜백으로 result를 받아 내부 코드가 비대해지는 일이 많았는데 람다로 구현 되면서 더 직관적이고 유지, 보수가 쉬운 코드가 될 수 있을거 같아 기대중이다.