많이들 액티비티의 생명주기하면 공식처럼 알 것이다. 처음 액티비티가 시작하면 onCreate
메서드를 타고 onStart
onResume
를 거쳐 실행이 되고 종료되면 또 그에 맞게 플로우를 타리라고. 그치만 이 포스트에서는 다 알법한 이야기보다는 자세한 이야기를 해볼까 한다.
우선순위가 더 높은 앱이 메모리가 필요하다면 앱은 언제든지 종료될 수 있다. 그렇게 때문에 onStop
, onDestroy
메서드는 반드시 실행된다는 보장이 없다.
onDestroy
메서드가 불리는 것은 finish()가 호출될 때 만으로 이해하기 쉽다. 근데 시스템에서 액티비티를 제거할때도 이 메서드가 불린다.
심지어 하나의 태스크만 사용할 때는 메모리 사용이 많아지면서 OOM이 발생하지만, 앱에서 여러 태스크를 사용한다면 OOM이 발생하기 전에 메모리 문제 가능성을 줄일 수 있다. 가용 메모리 3/4가 넘을 때 포그라운드의 태스크를 우선시하면서 메모리를 확보하기 위해 백그라운드의 태스크에서 액티비를 종료하는 것이다.
시스템에 의해서도 액티비티는 제거될 수 있기 때문에 태스크의 액티비티 목록이 유지된다고 가정해서는 안된다.
시작할 때
- onCreate -> onStart -> onResume
화면 회전할 때(가로/세로)
- onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume
다른 액티비티가 위에 뜰 때 or 전원키로 화면 off할 때 or 홈키로 앱 나갈 때
- onPause -> onStop
back 키로 액티비티 종료할 때
- opPause -> onStop -> onDestroy
back 키로 기존 액티비티에 돌아올 때 or 홈키로 나갔다가 돌아올 때
- onRestart -> onStart -> onResume
다이알로그 테마 액티비티나 투명 액티비티가 위에 뜰 때
- onPause
activity api 문서를 보면 3가지 라이프타임으로 구분한다
여기싀 from ~ to
는 from < 라이프타임 < to
이다.
Activity는 onPause()
이전까지가 포그라운드 상태이고, onPause()
까지 실행된다면 일부가 보이면서 백그라운드 상태가 된다.
또 하나 혼동하지 말하야할게 있다. setContenView()
는 onStart()
에서부터 화면에 보이는 것일까?
아니다. onCreate
부터 onResume
까지는 하나의 Message 처리이므로, setContentView
의 결과 화면은 onResume 이후에 보인다.
onStart()부터 가시 라이프타임이라는 것은 액티비티가 화면에 보이지 않다가 다시 보일 때는 여기부터 실행된다는 의미다. onResume()도 마찬가지이다. 백그라운드에 있으면서 아직 보이는 상태에 있다가 포그라운드로 오면 onResume()부터 실행된다
onCreate()에서 finish()를 호출하면 다른 생명주기 메서드를 거치지 않고 곧바로 onDestroy()를 실행한다.
onActivityResult()는 onResume()보다 먼저 실행된다. onActivityResult()에서 가져온 결과를 업데이트하고 onResume()에서도 최신 데이터를 업데이트해야 할 때, 이 실행ㅇ 순서를 주의하자.
시스템에서 초기화를 위해서 사용하는 것이므로 앱에서 쓰는 것은 권장하지 않는다.
액티비티 A->B 로 전환한다고 하면 A는 호출자, B는 피호출자라 하자
액티비티를 시작하는 방법은 startActivity()
와 startActivityForResult()
메서드를 호출하는 것이다.
그러나 AndroidX Activity와 Fragment에서는
startActivityForResult()
는 메모리 부족으로 인해 프로세스와 액티비티가 없어질 수 있기 때문에 deprecated되고 콜백함수로 바뀌었다.
출처 : 안드로이드 공식 문서
startActivity()
는 Context의 메서드이기 때문에 Activity 뿐만 아니라 Service, BroadcastReceiver, Application 어디서든 startActivity()를 실행할 수 있다. 또한, startActivity()
는 피호출자에 데이터를 전달하기만 한다. 이를 통해 시작된 피호출자에서 getCallingActivity()
와 getCallingPackage()
메서드는 null을 리턴한다.
deprecated 됐지만 startActivityForResult()
는 Activity의 메서드이다. 액티비티끼리만 데이터를 주고 받을 수 있다.
호출자와 피호출자가 다른 태스크에 속해있다면 onActivityResult()에서 결과를 다시 받을 수 없다. -> 그치만 현재는 콜백함수로 부르기 때문에 다를 수 있음
Activity A -> Activity B -> Activity C
인 상황에서 C에서 A로 결과를 전달하고 싶다면 어떻게 해야할까?
Intent.FLAG_ACTIVITY_FORWARD_RESULT 플래그를 추가하면 된다. 근데 이것도 잘 사용해야 데이터가 전달이 된다. 아래의 케이스들을 살펴보자
1) 실패 케이스1 : RuntimeException
Activity A startActivityForResult()
-> Activity B startActivityForResult()
-> Activity C setResult
2) 실패 케이스2 : 데이터가 정상적으로 전달되지 않음
Activity A startActivityForResult()
-> Activity B intent add flags
, startActivityForResult()
-> Activity C setResult
3) 성공
Activity A startActivityForResult()
-> Activity B intent add flags
, startActivity()
-> Activity C setResult
Activity A -> Activity B인 상황일 때, A는 onPause()와 onStop()을 실행하고 B는 onCreate()부터 onResume()을 실행한다.
피호출자가 뜨고 난 이후에야 onStop()이 필요한지 알 수 있기 때문에 해당 순서를 갖는다.
이 경우에는 위의 경우와 반대다. 이 때의 생명주기는 역순이다.
onCreate(), onStart(), onResume()
는 super 함수를 먼저 실행한다.
onPause(), onStop(), onDestroy()
는 super 함수를 나중에 실행한다.
생명주기를 시작할 때는 뭔가를 만들어내는 일이 많고, 끝날 때는 정리하는 일이 많다는 것을 생각하자.
finish() 메서드는 리턴을 대신한 것도 아니고 리턴을 포함한 것도 아닌, 종료하라고 Message를 보내는 함수다.
그러므로 이 메서드 호출 위치가 끝일 때만 리턴이 필요 없는 것이지 메서드 중간이라면 리턴은 반드시 필요하다.
여기까지가 액티비티 생명주기에 대한 딥한 이야기의 끝이다. 자세한건 아래 레퍼런스로 연결한 책의 챕터 5를 읽으면 더 이해하기 쉬울 것이다! 책 읽고 정리한 포스트와 다름이 없기 때문이다.
super 함수와 메서드 이름이 같아서 읽는 사람에게 혼동을 주지 말자 등.. 당연한 이야기나 굳이 자세하게 쓸 필요 없는 내용들은 쳐내고 핵심만 넣었기 때문에 책을 사서 읽는 것을 추천한다!