본문 바로가기

Kotlin/안드로이드 공부

Android Activity Result API

728x90

기존에 사용하던 startActivityForResult() & onActivityResult() 를 대체하는 새로운 Activity Result API 가 나왔다.

기존 API 의 단점

- 강한 결합으로 코드를 다른 곳으로 분리시킬 수 없다.

- 개발자의 부주의로 casting error 가 발생할 수 있다.

- null pointer exception 역시 발생하기 쉬운 구조다.

 

새로운 API 의 장점

- 원하는 Activity Request마다 registerForActivityResult를 실행하기 때문에 requestCode가 존재하지 않는다.

- onActivityResult 를 override 할 필요가 없으므로  boilerplate code 가 줄어든다.

- 하나의  launcher 는 하나의 contract 를 실행하고 그 결과를 하나의 callback 으로 반환한다.

 

사용 방법

액티비티에서 registerForActivityResult 함수를 사용해서 Callback을 등록해준다.

인자로는 ActivityResultContracts 클래스의 Static 함수들을 넣어준다.

Result를 받기위해서 Activity를 실행하는 StartActivityForResult() 등의 함수를 넣어준다.

 

람다식에는 result로 받아온 값을 어떻게 사용하는지 정의해준다.

인자로 받아온 result객체를 이용하면, resultCode와 data에 접근할 수 있다.

 

위에서 정의한 내용을 launch 함수로 실행시켜 주면 된다.

 

코드

(java)

	private ActivityResultLauncher<Intent> ContractStartActivityResult =
            registerForActivityResult(
                    new ActivityResultContracts.StartActivityForResult(),
                    new ActivityResultCallback<ActivityResult>() {
                        @Override
                        public void onActivityResult(ActivityResult result) {
                            if (result.getResultCode() == Activity.RESULT_OK) {
                                final String strInput = result.getData().getStringExtra(Constant.RESULT_INPUT);
                                ((TextView) findViewById(R.id.input)).setText(strInput);
                            }

                        }
                    });
ContractStartActivityResult.launch(intent)

 

(kotlin)

 activityLauncher = activity.registerForActivityResult(
                ActivityResultContracts.StartIntentSenderForResult()
            ) { result ->
                if (result.resultCode == Activity.RESULT_OK) {
					// something..
                }
                it.onComplete()
            }
val pendingIntent = MediaStore.createDeleteRequest(resolver, uriList)
activityLauncher.launch(
    IntentSenderRequest.Builder(pendingIntent.intentSender).build()
)

 

ActivityResultContracts 에는 미리 빌드된 ActivityResultContract 클래스가 여러 개 포함되어 사용할 수 있다.

https://developer.android.com/reference/kotlin/androidx/activity/result/contract/ActivityResultContracts

 

ActivityResultContracts  |  Android Developers

androidx.car.app.managers

developer.android.com

 

또한, 개발자가 필요한 유형의 Custom Contracts 를 직접 만들 수도 있다.

(java)

public class MainContract extends ActivityResultContract<String, String> {

    @Override
    public Intent createIntent(Context context, String strSendText) {
        Intent intent = new Intent(context, SubActivity.class);
        intent.putExtra(Constant.SEND_TEXT, strSendText);
        return intent;
    }

    @Override
    public String parseResult(int resultCode, Intent intent) {
        if (resultCode == Activity.RESULT_OK) {
            if (intent != null) {
                return intent.getStringExtra(Constant.RESULT_INPUT);
            }
        }

        return "";
    }
}
// Custom contract
    private ActivityResultLauncher<String> CustomContractStartActivityResult =
            registerForActivityResult(
                    new MainContract(),
                    new ActivityResultCallback<String>() {
                        @Override
                        public void onActivityResult(String strResult) {
                            ((TextView) findViewById(R.id.input)).setText(strResult);
                        }
                    }
            );
CustomContractStartActivityResult.launch("hi");

 

(kotlin)

class MainContract : ActivityResultContract<String, String>() {

    override fun createIntent(a_context: Context, strSendText: String): Intent {
        return Intent(context, SubActivity::class.java).apply {
            putExtra(Constant.SEND_TEXT, strSendText)
        }
    }

    override fun parseResult(resultCode: Int, intent: Intent?): String? =
            if (resultCode == Activity.RESULT_OK) intent?.getStringExtra(MainActivity.Constant.RESULT_INPUT)
            else ""

}
    // Custom contract
    private val customContractStartActivityResult =
            registerForActivityResult(MainContract()) { result ->
                result?.let {
                    input.text = it
                }
            }
customContractStartActivityResult.launch("hi")