액티비티를 호출하고 결과를 받아오기 위해
Deprecated 된 startActivityForResult 대신 ActivityResultLauncher 를 사용할 수 있다.
startActivityForResult 는 왜 Deprecated 됐는가?
활동에서 결과 가져오기 | Android 개발자 | Android Developers
활동에서 결과 가져오기 개발자 앱 내의 활동이든 다른 앱의 활동이든 다른 활동을 시작하는 것이 단방향 작업일 필요는 없습니다. 다른 활동을 시작하고 다시 결과를 받을 수도 있습니다. 예를
developer.android.com
위 공식문서에서 자세히 살펴볼 수 있는데,
결과를 얻기 위해 액티비티를 시작할 때, 메모리 부족으로 인해 프로세스와 액티비티가 소멸될 수 있기 때문이다. (특히, 카메라 사용과 같이 메모리를 많이 사용하는 작업의 경우 소멸 확률이 매우 높음)
그렇게 되면, startActivityForResult 를 사용한 경우 onActivityResult CallBack에서 결과를 받아오지 못할 수 있다.
하지만 CallBack 을 사용하는 ActivityResultLauncher 를 반환하는 registerForActivityResult 를 사용할 경우 콜백 메소드 등록을 통해 결과값을 받아올 수 있다.
간단하게 요약하면 콜백을 분리하여 항상 콜백을 받을 수 있도록 하는 것이다.
1️⃣ 사용하기
위와 같이 2개의 다른 액티비티로 이동하는 버튼을 만들고
이동한 액티비티에서 보낸 결과를 받아와 출력하는 코드를 작성해보려고 한다.
private val activityResultLauncher : ActivityResultLauncher<Intent> = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
){
// SubOne에서 결과를 받아옴
if(it.resultCode == ONE){
val intent = it.data
val returnValue = intent!!.getStringExtra("one")
Toast.makeText(this, returnValue.toString(), Toast.LENGTH_SHORT).show()
}
// SubTwo에서 결과를 받아옴
else if(it.resultCode == TWO){
val intent = it.data
val returnValue = intent!!.getStringExtra("two")
Toast.makeText(this, returnValue.toString(), Toast.LENGTH_SHORT).show()
}
}
registerForActivityResult 를 이용하여 콜백 메소드를 등록해준다.
ActivityResultContracts 를 통해 결과를 생성하는 데 필요한 입력 유형과 결과의 출력 유형을 정의할 수 있다.
일반적인 startActivityForResult 와 유사하게 사용하려면 StartActivityForResult 로 지정하면 된다.
콜백메소드만 분리했으므로 결과를 받을 때 사용할 resultCode 만 정의해주면 되고 요청할 때 필요한 requestCode 는 작성하지 않는다.
registerForActivityResult는 프래그먼트나 액티비티를 만들기 전에 호출하는 것이 안전하므로 반환되는 ActivityResultLauncher 인스턴스의 멤버 변수를 선언할 때 직접 사용하는 것이 좋다.
resultCode 는 임의로 작성하였다.
인텐트로 resultCode를 정의하는 형식으로 하거나,
런처를 여러개 만드는 방식으로도 처리를 할 수 있다.
이제 두개의 액티비티로 이동하는 버튼 기능을 각각 정의해주고,
이동한 액티비티에서는 돌아가는 버튼을 누르면
정해진 resultCode 를 통해 값을 전달하도록 한다. 위 방식은 기존 방식과 차이가 없다.
그러면 위와 같이 액티비티에서 보낸 값을 resultCode 를 통해 받을 수 있다.
2️⃣ Permission
private val permissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
){ isGranted: Boolean ->
if(isGranted){
Toast.makeText(this, "허가", Toast.LENGTH_SHORT).show()
}
else{
Toast.makeText(this, "실패", Toast.LENGTH_SHORT).show()
}
}
아까 살펴본 ActivityResultContracts 에서 RequestPermission을 통해 권한을 요청하는 코드를 작성해주고
// 카메라 권한 요청 - 1
perButton.setOnClickListener {
if(ContextCompat.checkSelfPermission(
this@MainActivity,
Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED){
Toast.makeText(this@MainActivity, "이미 권한이 있습니다.", Toast.LENGTH_SHORT).show()
}
else{
permissionLauncher.launch(Manifest.permission.CAMERA)
}
}
권한 검사를 해 launch를 해주면 쉽게 권한을 요청할 수 있다.
그런데, RequestPermission 의 내부구조를 살펴보면
내부에서 이미 권한 검사를 하는 것을 알 수 있다.
// 카메라 권한 요청 - 2
perButton.setOnClickListener {
permissionLauncher.launch(Manifest.permission.CAMERA)
}
따라서 권한 검사 없이 그냥 바로 호출해도 이상없이 작동한다.
https://github.com/HanYeop/AndroidStudio-Practice2/tree/master/ActivityResultLauncher
GitHub - HanYeop/AndroidStudio-Practice2: (2021.05.20~) 안드로이드 학습 내용 저장소
(2021.05.20~) 안드로이드 학습 내용 저장소. Contribute to HanYeop/AndroidStudio-Practice2 development by creating an account on GitHub.
github.com
참고
https://developer.android.com/training/basics/intents/result?hl=ko
https://developer.android.com/training/permissions/requesting