오늘은 코틀린에서는 ActivityForResult가 deperated 되어 있어서 이를 대체할 ActivityResultLanuncher를
소개하겠습니다.
ActivityResultLanuncher를 사용하는 이유
-엑티비티에서 데이터를 받아오기 위해서 입니다.
엑티비티 A와 B가 있으면 A에서 B엑티비티를 생성 후에 B엑티비티에서 A엑티비티로 데이터를 받아오고 싶을 때 사용합니다.
ex) -현재 실행중인 앱의 엑티비티A에서 갤러리 앱의 엑티비티 B로부터 사진을 갖고오고 싶을 때
ActivityForResult가 Deperated된 이유
1)AndroidX Activity와 Fragment에 도입된 ActivityResult API 를 안드로이드 공식문서에서 적극 권장함
2)결과를 얻기 위해 엑티비티를 시작할 때 메모리 부족으로 인해 프로세스와 엑티비티가 소멸될 수 있음.
(특히 카메라 사용과 같이 메모리를 많이 사용하는 작업의 경우 소멸 확률이 매우 높음)
-기존 방법은 Activity에서 startActivityResult를 통해서 콜백을 등록하고 onActivityResult에서 콜백을 처리하므로
두 메서드가 같은 곳에서 구현을 해야하는데 메모리 부족으로 제대로 동작이 안될 수 있다.
ActivityResultLauncher와 ActivityForResult의 차이점
1)Activity ResulAPI는 다른 엑티비티를 실행하는 코드에서 결과 콜백을 분리한다.
-원래 기존의 startActivityForResult 메서드를 사용하면 항상 onActivityResult에서
콜백을 받아서 처리했지만 이렇게 할 경우 메모리가 부족해져서 Activity가 사라질
수 있다. 이 것을 방지하기 위해서 Activity를 실행하는 부분과 Result Callback 부분을
분리해서 만들어 주었다.
-registerForActivityResult() 메서드는 콜백을 등록하는 역할을 해준다.
2)RequestCode가 사라짐
-Result Callback 부분을 분리해서 구현했기 때문에 requestCode도 필요 없음.
3)Activity가 종료되었다가 다시 만들어져도 Result값을 기다리게 할 수 있음.
3-1)A 액티비티와 B 액티비티가 있을 때,
startActivityResult메서드와 onActivityResult메서드를 사용해서 구현할 경우
- A -> B 실행, 메모리가 부족해서 A가 소멸됨.
- B 액티비티 종료 후 setResult() 메서드로 결과값 넘김
- A가 소멸됐다가 다시 생성돼서 B에게 결과값을 요청한 줄 모름.
3-2)ActivityResultLauncher객체와 registerForActivityResult()를 사용한 경우
- A -> B 실행, 메모리가 부족해서 A가 소멸됨.
- B 액티비티 종료 후 setResult() 메서드로 결과값 넘김
- A가 다시 생성돼도 registerForActivityResult() 메서드가 다시 콜백을 등록해 줘서 결과값을 받아온다.
-아직 정확하게는 이해가 아직 잘 안되지만 onCreate()에서 registerActivityResult를
사용해서 콜백메서드를 등록해주면 엑티비티가 메모리부족으로 소멸되었다가
재생성되어도 결과값을 받아올 수 있는 것 같다.
예제
MainActivity.kt
class MainActivity : AppCompatActivity(), View.OnClickListener {
val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
//ActivityResultLauncher<T>객체를 생성해주고 초기화 해준다.
//T는 내가 호출할 엑티비티에서 결과값으로 받아올 자료형을 말한다.
lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
val TAG = "MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
binding.btnMain.setOnClickListener(this)
//RegisterActivityResult(Contract자료형, 콜백메서드)를 이용해서
//ActivityResultLauncher를 초기화 해준다.
activityResultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult())
{//Result 매개변수 콜백 메서드
//ActivityResultLauncher<T>에서 T를 intent로 설정했으므로
//intent자료형을 Result 매개변수(콜백)를 통해 받아온다
//엑티비티에서 데이터를 갖고왔을 때만 실행
if (it.resultCode == RESULT_OK) {
//SubActivity에서 갖고온 Intent(It)
val myData: Intent? = it.data
val address = it.data?.getStringExtra("KEY1") ?: ""
Log.e(TAG, address)
}
}
}
override fun onClick(v: View?) {
when (v?.id) {
//버튼을 누르면 메뉴 엑티비티가 실행되게 하였다.
//launch메서드를 이용해 intent를 실행하고 새 엑티비티로부터 응답을받는다.
//그리고 RequestCode가 사라졌다.
binding.btnMain.id -> {
val intent = Intent(applicationContext, SubActivity::class.java)
activityResultLauncher.launch(intent)
}
else -> {
}
}
}
}
SubActivity.kt
class SubActivity : AppCompatActivity(), View.OnClickListener {
val binding by lazy { ActivitySubBinding.inflate(layoutInflater) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
binding.btnSub.setOnClickListener(this)
}
//버튼 클릭 리스너 메서드
override fun onClick(v: View?) {
when (v?.id) {
binding.btnSub.id -> {
val intent = Intent(applicationContext, MainActivity::class.java).apply {
//엑티비티에서 갖고올 데이터
putExtra("KEY1", "bbbbb")
//데이터 전달이 성공했을 때의 변수 값 저장
// Result_ok = -1 일 때 엑티비티에 전달된다.
}
setResult(RESULT_OK, intent)
//엑티비티 종료
if (!isFinishing) finish()
}
else -> {
}
}
}
}
참고
https://kimyunseok.tistory.com/40
https://kimyunseok.tistory.com/39?category=1035300
https://stickode.com/detail.html?no=2415
'안드로이드 공부 & 앱' 카테고리의 다른 글
[안드로이드] JetPack Navigation 개념 정리 및 예제 (0) | 2022.04.16 |
---|---|
[안드로이드] 버튼 클릭 리스너로 확인하는 옵저버 패턴-1편 (0) | 2022.04.13 |
운동친구 어플 레이아웃 설계화면 (0) | 2022.02.12 |
[안드로이드/코틀린] 카메라/갤러리 사진 이미지뷰에 로딩하기 (0) | 2022.01.28 |
[Android/코틀린/PHP] Retrofit2를 이용한 간단한 서버 클라이언트 통신 예제 (0) | 2021.12.05 |
댓글