본문 바로가기

Android - 기능

[Android] startActivityForResult @deprecated

#What

startActivityForResult -> onActivityResult 짝꿍이 Deprected 됐으므로 대체 API를 알아봅시다.

1)일반적인 Activity이동 

 

*디벨러퍼에서도 AndroidX를 사용한다면 대체 API를 사용하라고 적극 권장 중입니다

  it is strongly recommended to use the Activity Result APIs introduced in AndroidX Activity and Fragment.

  https://developer.android.com/training/basics/intents/result

 

 

#기존 방식

 startActivityForResult을 RequestCode를 인자로 호출 후, onActivityResult에서 RequestCode 분기 후 결과 처리

 

#대체 방식 

=> registerForActivityResult  를 사용

인자 : 1) ActivityResultContracts  2) ActivityResultCallback

리턴 : ActivityResultLauncher (activity 시작할 수 있게 해쥼)

lateinit var launcher: ActivityResultLauncher<Intent>

  override fun onCreate(savedInstanceState: Bundle?) {
                        ...
        //1) intent 생성 =  기존 동일
        val intent = Intent(applicationContext, SecondActivity::class.java)
        
        //2) resultCallback 등록 후 ActivityResultLauncher 멤버로 저장
        launcher = registerForActivityResult(
            ActivityResultContracts.StartActivityForResult(), // 인자 1) Contract
            ActivityResultCallback<ActivityResult> { result -> // 인자 2) ActivityResultCallback
                val resultCode = result.resultCode
                val dataIntent = result.data
                Log.i("syTest","result : ${result.toString()}")
            }
        )

        findViewById<TextView>(R.id.tv_hello).setOnClickListener {
        //실제 activity 이동 코드 
            launcher.launch(intent)
        }
    }
}
  • Intent 작성법은 기존과 동일 
  • ActivityResultCallback이 기존의 onActivityResult(int requestCode, int resultCode, Intent data) 를 대신함
  • launch 요청 마다 각각의 ActivityResultCallback이 등록돼있으므로, requestCode가 사라짐
  • ActivityResultContracts에 미리 정의 돼 있는 StartActivityForResult()를 가져와 사용할 수 도 있고, Custom ActivityResultContract를 재정의해 사용할 수 도 있음

 

 

#왜 callback 등록과, 액티비티 launch를 분리했을까?

콜백 등록 in Developer

[자체 해석...]

startActivityForResult 호출로 카메라와 같은 메모리 사용량이 많은 작업을 실행하는 경우 process와 activity가 

destory 되는경우가 발생합니다. 

이 때문에 Activity Result API는 (카메라) 호출을 실행한 Code와 result callback을 분리 합니다.

다시 process와 activity가 재생성 됐을 때 result callback을 사용 할 수 있으려면

사용자 입력 or 비즈로직에 의해 activity 이동이 이루어졌더라도, activity가 (재)생성 될 때 마다 무조건 result callback은  등록이 돼야 합니다.

 

즉, 실제 액티비티 launch코드가 어느 부분에 쓰이던지간에 result callback은 액티비티 재생성 될 때 무조건 다시 등록 돼야 하므로 callback 등록과 액티비티 launch를 분리시킨 것으로 보입니다

  • 1) activity 생성 될 때 무조건 result callback 등록  및 launcher 획득   
  • 2) 실제 launch(activity 이동) 코드는 원하는 부분에
  • 고로 onCreate()/onStart() 내부에서 콜백을 register 해줘야 합니다 -> Activity 생성/재생성 될 때 마다 등록 해야 하므로

 

*결과 콜백을 액티비티가 started 된 이후 등록하게 되면 아래와 같은 에러를 만나게 됩니다

java.lang.RuntimeException: Unable to resume activity {~~.MainActivity}: java.lang.IllegalStateException: LifecycleOwner ~~.MainActivity@efd3d7a is attempting to register while current state is STARTED. LifecycleOwners must call register before they are STARTED.

 

 

# Permission 체크는 어떻게?

val launcher = registerForActivityResult(ActivityResultContracts.RequestPermission(),
    ActivityResultCallback { isGranted->
        Log.i("syTest", "isGranted : $isGranted")
    })

findViewById<TextView>(R.id.checkPermission).setOnClickListener {
    if(ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)== PackageManager.PERMISSION_GRANTED){
        Log.i("syTest", "granted O")
    }else{
        Log.i("syTest", "granted X")
        //launcher실행 - 권한 팝업 뜸 
        launcher.launch(Manifest.permission.CAMERA)
    }
}



# API 바뀐 결과 장점은?

  1. A -> B Activity 이동 후 다시 A로 돌아 갈 때, A가 destroy 됐다가 재생성 되는 경우에도 Callback을 등록하므로 동작에 문제가 없습니다! (B로 부터 result 값을 받아야 할 경우)
  2. REQUEST_CODE가 사라졌습니다!! 새로 정의할 무의미한 숫자를 고민하지 않아도 됩니다
  3. Request가 많아지면서 onActivityResult 분기가 늘어나고 비대해지는 부분도 해결이 되겠습니다
  4. launch와 result callback의 흐름을 보기가 수월 해졌습니다(보다 유기적으로 연결돼 보입니다)

 

문제 있을시 알려 주세요.

 

좋은 하루 되세요!