일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- PagingLib
- google play
- 동영상
- mvvm
- SwiftUI Tutorial
- databinding
- Android 13
- 테스트 자동화
- junit
- Koin
- RxKotlin
- paging
- Observable
- Animation
- Kotlin
- MotionLayout
- node.js
- list
- Android
- rx
- SWIFTUI
- Reactive
- MediaPlayer
- 인앱결제
- mysql
- GCP
- node
- php
- android13
- MediaSession
- Today
- Total
봄날은 갔다. 이제 그 정신으로 공부하자
여러개의 Activity 한번에 종료하기 본문
개발하면서 흔히 겪는 상황이 여러개의 화면을 한꺼번에 종료해야되는 상황 입니다.
아래와 같이 다양한 해결 방법이 있습니다.
- Activity + Fragment 구조를 통한 해결 방법
- Activity간 Result 전달 방식을 사용한 해결 방법
- Task Affinity를 사용한 해결 방법
문제 해결 방식은 위 3가지 방식 말고도 몇가지가 더 있지만 대표적인 방법 3가지만 기술하였습니다.
아무래도 Task Affinity 방식 외의 방식은 여러개의 화면을 한꺼번에 종료하기에는 최적화 되지 않은 땜빵이라는 느낌이 강해서
해당 문서에서는 "Task Affinity를 사용한 해결 방법"을 중점으로 설명합니다.
나머지 두가지 방식에 대해서는 추후 기회가 되면 별도의 문서로 기술하도록 하겠습니다. (안한다는 얘기임.)
여러개의 화면을 한꺼번에 종료하는 상황을 아래와 같다고 가정해봅니다.
사용자는 화면 A → B → C → D로 이동하였고 종료 버튼을 누르는 경우 D, C 화면을 종료하고 화면 B로 돌아가야 합니다.
Activity + Fragment 구조를 사용한 해결 방법
간단히 설명하면 Activity에 포함되는 화면으로 표시되는 화면의 영역 및 Fragment의 Insert와 remove를 Activity에서
제어합니다.
그러므로 여러개의 화면을 한꺼번에 종료해야 할 필요가 있을 때 Activity + Fragment 구조를 사용하기도 합니다.
화면 A를 ActivityA로 만들고 화면 B,C,D를 Fragment로 만든 다음에 해당 Fragment들을 관리하는 ActivityBCD를 만들면
화면 D종료 시 ActivityBCD에서 Fragment를 D에서 B로 변경하면 화면 이동이 간단해집니다.
하지만 Fragment는 Activity 없이 독립적으로 존재 할 수 없기 때문에 구조 및 코드가 복잡해지는 문제가 발생합니다.
화면 이동 시나리오가 A → B → C → D 순서이면 큰 문제가 없지만 A → C → B → D 등과 같이 무작위 접근이 가능한 시나리오인 경우, 범용성이 낮고 ActivityBCD에서 화면 이동 관련 스택 관리를 해주어야 하기 때문에 Activity + Fragment 구조는 화면을 관리하는데 매우 많은 비용을 소모하게 됩니다.
Activity간 Result 전달 방식을 사용한 해결 방법
개발 중 자주 사용하는 방식인 Activity간 데이터를 주고 받는 startActivityForResult + setResult 방식을 조금만 응용하면
개발 가능하므로 의외로 개발자들이 많이 사용하는 방식입니다.
이 방식이 잘 못된 방식은 아니지만 기능 개발을 위해 화면 B, C, D간 startActivityForResult + setResult를 사용해야 하므로
조금은 번거로운 방식이라고 할 수 있습니다.
자세한 예시는 아래와 같습니다.
여러가지 변수를 고려하면 실제 코드는 이것보다 더 복잡해집니다.
class ActivityB : AppCompatActivity(){
fun showB{
startActivity(Intent(this@ActivityB, ActivityC::class.java))
}
}
class ActivityC : AppCompatActivity(){
// 결과를 받아 확인 후 자신을 종료해야 하면 종료하는 함수
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(resultCode == Activity.RESULT_OK){
data?.let{
if(data.getBooleanExtra("MULTI_FINISH", false)){
this@Activity.finish()
}
}
}
}
// 결과를 받을 수 있게 ActivityD를 호출하는 함수
fun showD{
startActivityForResult(Intent(this@ActivityC, ActivityD::class.java), 0)
}
}
class ActivityD : AppCompatActivity(){
// 자신을 종료하면서 결과를 받은 Activity도 같이 종료 요청하는 함수
fun multiFinish{
val intent = Intent()
intent.putExtra("MULTI_FINISH", true)
setResult(Activity.RESULT_OK, intent)
this@ActivityD.finish()
}
}
직접 개발자가 코딩으로 Activity간 이동 및 종료를 관리하므로 여러가지 시나리오에 대한 대응이 가능하므로 범용성이 높은 방식이지만 관련 부분을 모두 개발자가 개발 및 관리해주어야 하므로 적지 않는 리소스가 소모됩니다.
Task Affinity를 사용한 해결 방법
Task Affinity를 사용한 여러개의 Acitivity 종료 방식은 android 초창기부터 지원되는 기능인데 의외로 개발자들에게 외면 받는 방식입니다. 아무래도 해당 방식은 여러개의 Activity를 종료할 때만 사용되어 개발자들에게 낮설고 다른 방식으로 우회 처리 가능하다보니 외면 받는 것 같습니다.
Task Affinity를 사용한 해결 방식은 아래와 같습니다.
우선 같이 종료되어야 하는 Activity C와 D만 동일한 TaskAffinity로 선언합니다.
A와 B는 상관 없습니다.
<activity android:name=".view.ActivityA"/>
<activity android:name=".view.ActivityB"/>
<activity android:name=".view.ActivityC"
android:taskAffinity="com.als2019.multiFinish"/>
<activity android:name=".view.ActivityD"
android:taskAffinity="com.als2019.multiFinish"/>
여기서 중요합니다.
ActivityB에서 ActivityC를 실행 시켜줄 때 NEW TASK로 실행 시켜줍니다. ← "이거 추가하지 않으면 기존 task와 함께 관리되어 멀티 finish가 동작하지 않습니다."
자세한 코드는 아래와 같습니다.
class ActivityB : AppCompatActivity(){
fun showB{
val intent = Intent(this@ActivityB, ActivityC::class.java)
intent.setFlag(Intent.FLAG_ACTIVITY_NEW_TASK) // ← NEW_TASK 추가하지 않으면 기존 task와 같이 관리됩니다.
startActivity(intent)
}
}
class ActivityC : AppCompatActivity(){
fun showD{
startActivity(Intent(this@ActivityC, ActivityD::class.java))
}
}
class ActivityD : AppCompatActivity(){
// 자신을 종료하면서 같은 task affinity로 묶인 ActivityC도 같이 종료한다.
fun multiFinish{
this@ActivityD.finishAffinity()
}
}
앞서 언급한 Activity간 Result를 전달하는 방식에 비해 코드가 매우 간단해진 것을 알 수 있습니다.
'android Tip' 카테고리의 다른 글
Coroutine - part1 (0) | 2020.12.25 |
---|---|
android 다양한 주변장치 연동 (NFC, USB) (0) | 2020.12.24 |
Custom 버튼 만들기 (0) | 2020.12.21 |
숫자에 콤마 추가 시 주의할 점 (0) | 2020.12.11 |
모두가 사용하지만 모두가 모르는 좌표계 이해하고 넘어가기 (0) | 2020.11.25 |