반응형
startActivityForResult
- 두번째 액티비티가 실행될 때 뭔가 처리를 하고 싶다면 첫번째 액티비티는 onPause()에서, 두번째 액티비티는 onCreate()에서 처리를 해주면 됨
- 하지만 다른 액티비티를 실행 후 다시 원래 액티비티로 돌아와 어떤 처리가 필요한 경우, statActivity가 아닌 startActivityForResult 메서드를 사용 (onResume()은 액티비티가 안 보였다 다시 보이면 무조건 호출되므로 딱 이 상황에 적절 x)
- startActivityForResult 메서드 사용하면 원래 액티비티로 돌아왔을 때 onActivityResult 메서드가 자동 호출 (여기서 작업 처리
💡 startActivityForResult 가 decreated 되면서 registerForActivityResult() 메서드를 사용한다.
registerForActivityResult
- Activity Result API에서 제공하는하는 API 의 일종으로 Activity 나 Fragment에 있을 때 결과 콜백을 등록할 수 있음
- ActivityResultContract와 ActivityResultCallback을 가져와서 다른 activity를 실행하는 데 사용할 ActivityResultLauncher를 반환 -> startActivity 나 startActivityForResult가 아닌 ActivityResultLauncher를 사용해 다른 액티비티를 실행
[MainActivity.kt]
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater) // 뷰바인딩 객체
val view = binding.root //뷰바인딩을 통해 레이아웃과 뷰가 결합 -> .root 를 통해 View 객체만를 뽑아내는(?)
setContentView(view)
binding.button.setOnClickListener {
val second_intent = Intent(this, SecondActivity::class.java)
//액티비티 안에서는 액티비티가 context를 상속받고 있으므로 this 넣어줌
//SecondActivity.kt를 가지고 만들어진 자바 파일, 자바가 컴파인된 클래스 파일을 지칭-> 클래스 지정 (reflection 개념)
// intent 객체를 전달해 실행시킴
//startActivity(second_intent) //메인 위에 second가 올라가는 상태
activityResultLauncher.launch(second_intent)
}
binding.button4.setOnClickListener {
val thrid_intent = Intent(this, ThridActivity::class.java)
activityResultLauncher.launch(thrid_intent)
}
}
// 사용자가 카메라를 사용해 찍고 돌아왔는지, 안 찍고 돌아왔는지에 따라 분기해 다르게 처리하는 등의 경우에 필요
//startActivityForResult 는 decrated 되어 launcher 를 사용한 방식 공부 필요
private val activityResultLauncher : ActivityResultLauncher<Intent>
activityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult())
{
// SubOne에서 결과를 받아옴
if(it.resultCode == 100){
binding.textView.text = "두번째 액티비티에서 돌아왔습니다."
}
// SubTwo에서 결과를 받아옴
else if(it.resultCode == 200){
binding.textView.text = "세번째 액티비티에서 돌아왔습니다."
}
}
}
[SecondActivity.kt]
second_binding.button2.setOnClickListener {
setResult(100) // resultCode : code 값, Intent(선택적) : 전달할 데이터를 Intent 객체로 만들어 저장
//setResult(Activity.RESULT_OK)
//RESULT_OK, RESULT_CANCELED, RESULT_FIRST_USER, RESULT_FIRST_USER + 1 과 같이 미리 정의되어 있는 변수값도 활용할 수 있음
//BACK 버튼을 눌러 종료하게 되면 CANCELED로 취급됨
finish() // 현재 액티비티 종료
}
https://velog.io/@ho-taek/Android-registerForActivityResult%EB%9E%80
💡 위 예제 코드처럼 내가 만든 액티비티를 실행하게 되면 액티비티 코드를 내가 다 가지고 있기 때문에 setResult()에 resultCode를 설정하고 registerForActivityResult 에서 resultCode로 분기해 여러 코드를 작성할 수 있다. 하지만 외부 저장소 관련 공부를 하다 보면 파일 관리 앱의 액티비티를 실행해 사용할 때가 있다.
/* 외부 저장소에 데이터 쓰기 */
// 파일 관리 앱의 액티비티 실행
val fileIntent = Intent(Intent.ACTION_CREATE_DOCUMENT) // 파일을 만들어 쓰는 옵션 줌
fileIntent.addCategory(Intent.CATEGORY_OPENABLE) //비로소 쓰기 위한 파일을 열 수 있음
fileIntent.type = "*/*" //전체
activityResultLauncher1.launch(fileIntent)
/* 외부 저장소에 데이터 읽기 */
val fileIntent = Intent(Intent.ACTION_OPEN_DOCUMENT) // 파일을 만들어 쓰는 옵션 줌
fileIntent.type = "*/*"
activityResultLauncher2.launch(fileIntent)
위와 같은 예제 코드에서는 파일 관리 앱의 액티비티를 내가 만든 앱에서 접근할 수가 없다.
쓰기와 읽기를 위해 액티비티를 실행한 후 다시 돌아와서 처리해야 하는 코드가 서로 다른 경우 같은 activityResultLauncher를 쓸 수가 없다.
액티비비티의 setResult()를 설정해주지 않는 이상 resultCode는 항상 RESULT_OK 이기 때문에 분기가 어렵다.
따라서 이 경우 activityResultLauncher를 각각 만들어 주는 처리가 필요할 것 같다.
이렇게 쓰는게 맞는지 모르겠는데 상당히 불편하고, 재사용성이 떨어지는 것 같다...
private val activityResultLauncher1 : ActivityResultLauncher<Intent> =
registerForActivityResult(ActivityResultContracts.StartActivityForResult())
{
when (it.resultCode) {
RESULT_OK -> {
//파일의 경로를 관리하는 객체를 얻어옴
val des1 = contentResolver.openFileDescriptor(it.data?.data!!,"w") // it.data?.data!!(사용자가 쓰기를 원하는 파일의 경로)를 가지고 file descriptor를 만듬
val fos = FileOutputStream(des1?.fileDescriptor) //파일 접근 스트림 생성
val dos = DataOutputStream(fos)
dos.writeInt(500)
dos.writeDouble(55.55)
dos.writeBoolean(true)
dos.writeUTF("문자열3")
dos.flush()
dos.close()
binding.textView.text = "다운로드 폴더에 저장"
}
}
}
private val activityResultLauncher2 : ActivityResultLauncher<Intent> =
registerForActivityResult(ActivityResultContracts.StartActivityForResult())
{
when (it.resultCode) {
RESULT_OK -> {
val des2 = contentResolver.openFileDescriptor(
it.data?.data!!,
"r"
) // it.data?.data!!(사용자가 쓰기를 원하는 파일의 경로)를 가지고 file descriptor를 만듬
val fis = FileInputStream(des2?.fileDescriptor) //파일 접근 스트림 생성
val dis = DataInputStream(fis)
val data1 = dis.readInt()
val data2 = dis.readDouble()
val data3 = dis.readBoolean()
val data4 = dis.readUTF()
dis.close()
binding.textView.text = "data1: ${data1}\n"
binding.textView.append("data2: ${data2}\n")
binding.textView.append("data3: ${data3}\n")
binding.textView.append("data4: ${data4}")
}
}
}
https://farmerkyh.tistory.com/1150
반응형
'Android' 카테고리의 다른 글
[안드로이드/Activity] 데이터 전달 (0) | 2023.03.18 |
---|---|
[안드로이드] CallBack 과 Listener (0) | 2023.03.11 |
[안드로이드/Activity] Intent 와 Activity 실행 (0) | 2023.03.10 |
[안드로이드/Activity] Activity란 무엇인가? (0) | 2023.03.08 |
[안드로이드/Menu] Popup Menu (0) | 2023.03.08 |