Activity Lifecycle

2020. 2. 23. 00:48android

1. 개념


 

먼저 액티비티가 무엇일까? 액티비티는 사용자와 상호작용하는 화면, 즉 UI가 그려지는 하나의 화면이라고 생각하면 쉽다. 쉽게 카카오톡화면, 카메라 화면 어떤 앱상에서의 모든 화면 등 사용자와 상호작용하는 하나의 화면을 의미한다. 물론.. 이런 상호작용하는 화면이라해서 전부 액티비티라 칭하지는 않는다. fragment란 개념도 있으니.. 여튼 여기선 액티비티가 단순히 무엇인지 알고가기 위해서 다시 한번 정의 해 본다.

 

ps)

추가적으로 용어를 하나 더 정리해 가자면 안드로이드 스튜디오에서는 콜백(call back) method란 말이 참 많이 나온다. 그럼 call back method가 무엇일까? call back method 란 다른 함수의 인자로써 이용되는 함수 또는 어떤 이벤트에 의해 호출이 되어지는 함수이다. 쉽게 말하면 어떤 메서드의 파라미터에 메서드를 전달하는 것이다. 이렇게 파라미터로 전달된 메서드에서 return되는 값을 받아서 본 메서드의 파라미터로 쓰이게 끔 하는게 콜백 메서드 인 것이다.  

 

 

2. Activity의 Lifecycle의 구성


안드로이드 스튜디오는 액티비티를 생성하고 삭제하기까지 6가지 콜백 함수를 통해서 관리 해 나간다. 즉 이벤트에 의해 호출되어지는 콜백 함수가 6개가 존재한다.

 

예를들면 액티비티를 생성하는 콜백 메서드가 있을 것이다. 또한 사용자가 액티비티 화면과 상호작용하고 있는데 갑자기 전화가 걸려온다면? 기존에 사용자가 상호작용하던 화면이 온전하게 보존되게 해주는 메서드 또한 존재할 것이다. 마찬가지로 액티비티가 사라지는 메서드도 존재할 것이다.

 

즉 이렇게 이벤트에 의해 불려지는 것이 콜백 메서드이고 액티비티의 라이프 사이클은 6개의 콜백 메서드로 구현되어진다.

 

 

 

 

 

 

 

 

 

1) onCreate(Bundle saveInstanceState)

 

먼저 onCreate() 콜백 메서드이다. 이 메서드는 액티비티가 생성될 때 시작되는 콜백 함수이므로 반드시 구현해야한다. 

액티비티는 layout 내에서 정의된 viewGroup을 setContent() 메서드를 통해서 하나의 객체가 되어진다. 이후 viewGroup내에서 선언된 view들(TextView,ImageView,EditText ...etc)에 대한 처리를 여기서 설정하게 된다. 예를들면 버튼을 클릭했을 때의 이벤트 정의를 onCreate()메서드를 통해서 선언해줘야 실제 유저의 반응에 따르는 이벤트가 발생하게 되는 것이다. 

 

cf) 매개변수로 saveInstanceState를 받는데 이것이 의미하는 것은 이전 액티비티의 저장상태를 bundle이란 자료형으로 저장해 놓는다.

간단하게 예를들자면 안드로이드는 화면을 회전시킬때 액티비티가 지워지고 다시 만들어지는데 만약 사용자가 회원가입을 하고있다가 갑자기 화면을 돌리게 되었을 때, 기존에 입력한 자신의 정보들을 그대로 가지면서 화면이 회전이 되어야한다. 따라서 saveInstanceState에 회전 이전의 액티비티 상황을 가져와서 bundle형으로 저장해 다시 onCreate() 콜백함수에서 기존에 정보를 갖는 액티비티로 다시 만드는 것이다. 

 

practice.java

이렇게 activity를 상속받으면 이제부터 practice.java는 액티비티로 쓰이게 된다. 그렇다면 이제 onCreate()함수에서는 어떤 일처리를 해야할까? 1. ui상에서 다룰 데이터들을 바인딩(연결)하는 것이다즉 xml상에서 만든 위젯들을 practice.java에서 선언한 변수와 서로 연결한다. 2.이벤트 처리를 정의한다. xml에서 만든 위젯이 사용자에 의해 어떤 이벤트가 처리되게 하고싶다면 onCreate()함수에서 정의하면 된다. 

 

practice_xml

 

이렇게 xml 상에 버튼 위젯을 하나 만들었다. 그러면 화면 중앙에 버튼이 하나 생긴다. 이제 이 버튼에 대한 이벤트 처리를 하고싶다면 practice.java에 바인딩을 해야한다. 

 

practice.java

 

바인딩을 도와주는 함수는 findViewById(int id)함수이다. argument로 R.id.just_button이라 되어져 있는데 R은 리소스들을 전체적으로 관리하는 전역 변수라 생각하면 된다. 따라서 R(resource에 존재하는).id(id가).just_buttom(xml상에서 선언한 버튼 id)을 practice.java의 button에 연결하는 것이다. 이렇게 객체와 view를 바인딩하기 위해서는 view를 갖고있는 viewGroup을 객체화시켜줘야한다. (그래야 메모리 올라와서 접근이 가능하기 때문)

 

practice.java

 

setContentView(View view) 메서드를 사용해서 practice.xml에서 선언된 view들로 ui를 만들겠다고 선언해야한다. 즉 layout을 가져오는? 것 정도로 생각하면 될 것같다. 여기서도 마찬가지로 매개변수가 R.layout.practice.xml이다. parameter로는 View view를 받는데 우리는 R.layout.practice.xml을 넘겨줬다. 즉 xml상에서 만들어지는 것이 곧 view라는 것이다. 이렇게 데이터(위젯, view)를 액티비티에 연결하고 생성하는 메서드이다. 이후 생성단계에서 멈추지 않고 시작단계로 넘어간다. 

 

2) onStart()

 

oncreate() 콜백함수에서 액티비티를 생성했으면 이젠 사용자에게 보여줘야한다. 즉 사용자에게 ui가 보여지기 위해 액티비티를 포그라운드로 보내 사용자와 상호작용을 할 준비를 마치는 역할을 담당하는 메서드이다. 착각하면 안되는 것이 이 단계에 오자마자 사용자에게 보여지는게 아니라 보여질 준비를 하는 것이다!! 이 메서드는 매우 빠르게 넘어가는 단계이므로 oncreate()함수와 마찬가지로 시작단계에서 머물지않고 onResume()단계로 넘어간다.

 

그럼 이 단계에서 무엇을 작업하면 좋을까? 예를 들면 로그인을 이미 한 사람이라면 로그인 창으로 넘어가지 않고 바로 메인창으로 넘어가는 것을 예를 들 수 있다. 또한 브로드캐스트리시버를 사용할 때도 이곳에 선언하여 사용하면 된다.

 

 

3) onResume()

실제로 onResume() 메서드에서 ui가 사용자에게 보여진다. 따라서 기존에 onCreate() 메서드에서 정의한 이벤트 처리가 실질적으로 사용자에 의해서 쓰이는 것이다.  여기서 쓰는 부분이 이 단계에 해당하는 것이고 만드는 것이 onCreate()인 것이다. 따라서 사용자가 ui를 떠나지 않는한(focusing이 유지되는 한) 라이프사이클은 이 단계에서 머물게 된다.

 

 버튼이 클릭되면 화면상에서 TextView의 text가 1씩 증가하는 이벤트를 처리하도록 만들 것이다.

 

따라서 onCreate() 메서드에서 버튼이 클릭되면 어떻게 동작할지를 이벤트 처리한다.

 

 

 

 

 

cf) 버튼이 눌렸을 때 처리되게 하는 것이 View.onClickListener에 담겨있다. 또한 우리는 우리가 원하는 대로 클릭 이벤트를 처리할 것이기 때문에 사람마다 이벤트 처리가 다를 것이다. 따라서 Anonymous class를 사용하여 별도로 클래스를 만들어 사용하지 않고 안드로이드 스튜디오에서 친절하게 만들어놓은 interface형인 onClickListener를 현재 class에서 본인이 처리되길 원하는 방향으로 이벤트 처리를 구현하고 이를 button에다가 button.setOnClickListener(new View.OnClickListener(){})처럼 클릭리스너를 버튼에 달아주면 버튼을 눌렀을 때의 처리를 만든 것이다.

 

다시 본론으로 돌아와서 이렇게 onCreate()에서 버튼에 대한 이벤트 처리까지 포함해 액티비티를 만들면 onResume()단계에서 사용자에 의해 버튼이 눌려 이벤트가 발생되므로 실질적 이벤트가 발생되는 부분이다.  

클릭 전

 

 클릭 후

그럼 이 단계에서 작업하면 좋은 것은 무엇일까? 위 그림처럼 버튼 클릭과 같은 사용자의 상호작용이 일어난 시점에서  onResume()단계가 실행된다. 따라서 onCreate()와 onStart()와는 다르게 계속 동적으로 사용자의 요구사항에 맞는 데이터들을 보여줘야한다. 따라서 사용자에게 보여질 데이터를 초기화하여 가져오는 코드를 이곳에서 작성하면 된다. 이유는 onPause() 메서드가 호출되고서 다시 onResume() 메서드가 호출되면 onPause()메서드에서 리소스를 해제한 것들을 다시 여기서 할당을해야 사용자에게 보여줄 수 있기 때문이다. 추가적으로 사용자의 정보를 임시 저장한 부분도 여기서 복구하면 될것이다.

 

4) onPause()

 

시스템이 사용자가 현재 activity를 떠났다는 것을 첫번째 신호로 이 method를 호출한다. 화면상에는 보여지지만 focusing을 잃어버려서 포그라운드에 띄워져있던 activity가 백그라운드로 내려오는 것을 말한다. 예를 들어보면 핸드폰 게임을 하다가 설정을 누르면 뒤에 배경이 흐릿해져 보이는 것을 경험해 봤다면 쉽게 이해가 갈 것이다. 또는 사용자가 앱을 사용하다가 홈버튼을 눌러 앱을 나가는 경우를 예를 들 수 있다.  

그런데 위의 예제처럼 설정창이든, 팝업창을 띄우든, 다이얼로그를 띄우든, 홈버튼을 눌러 나가든간에 전부 다 onPause 상태일까? 아니다. 가장 중요한 것은 현재 activity에 대한 focusing을 잃는 것이다. 또 예를 들면 단순히 팝업창은 팝업창이기 때문에 activity위에서 표시되어진다고 하더라도 activity가 아니기 때문에 onPause()가 호출되지 않는다. 추가로 팝업창을 하나의 activity로 만들어 기존의 activity위에 표시가 되어지면 현재 activity에 대한 focusing을 잃는 것이기 때문에 이는 onStop() 콜백 메서드가 호출된다. 따라서 onStop()으로 넘어가지않고 onPause()상태에 머무르려면 

 

res/values/style.xml

res폴더에 하위 폴더인 style에 위의 사진처럼 style을 선언한 뒤,

 

 

manifest에 투명성을 부여할 activity에 andorid:theme을 통해서 선언하면 이제 Window_transparent 액티비티는 투명성을 갖는 화면으로 안드로이드가 인식하기 때문에 intent로 인한 액티비티 전환임에도 불구하고 onStop() 단계로 가지 않고 onPause()단계에 머무르게 된다.

 

 

 

안드로이드는 투명한걸 모르나보다. 이전 화면은 보이지 않지만 로그를 찍어보면 onPause()상태에 멈춰있음을 알 수 있다.

 

그럼 onPause()에서는 어떤 작업을 하면 좋을까? onPause()에서는 onStop()되기 전의 상태이므로 onStop()에 들어설 준비를 하면 된다. 즉 쓸모없는 메모리 할당을 해제하는 것이다. 예를 들면 애니메이션 정지, cpu 리소스를 계속적으로 잡아먹는 일 정지, 사용자와 상호작용했던 정보 임시저장, 브로드캐스트기능 or 센서 핸들기능(GPS,카메라) 등 배터리를 잡아먹는 행위 등을 작업하면 좋다. 이유는 가끔 메모리에 모든 정보를 올렸다가 메모리가 부족하면 강제로 종료하기 때문에 기존에 정보들이 다 날라갈 수있기 때문이다. 따라서 임시로 값을 저장하거나 메모리에 올린 공간을 최소화해야한다.

 

예를들어 사용자와 상호작용했던 정보를 임시저장해 보겠다.

 

내가 데이터를 임시저장하는 방법은 SharedPreferences를 사용하는 방법이다. 이 방법은 많지 않은 데이터를 저장할 때 데이터베이스를 굳이 사용하지않고 안드로이드 상에서 저장하는 방법이다. 또한 SharedPreferences는 db처럼 key : value 방식으로 저장하고 한번 저장된 key는 삭제하지 않는 이상 영구 저장된다. 

 

그럼 getSharedPreferences("info",0)이 key 와 value형태로 구성된 걸까? 아니다. 여기서 info는 group을 의미하고 0은 만약 info라는 그룹이 없으면 새로 만들라는 것을 mode 0으로 안드로이드가 인식하기때문에 mode에 0을 줬다. 그렇게 preferences 변수로 기본 환경값을 가져오면 이제 실제로 key : value 상태로 저장하기위해 editor변수에 preferences.edit()를 할당해서 editor변수로 저장 및 삭제를 진행한다.

 

 

데이터를 저장하는 방법은 putString(key, value)를 사용하여 스트링인 value를 key와 짝짓는다.

이처럼 putBoolean, putInt 등 자료형마다 key : value 쌍을 이룰 수 있다. 그리고 apply()메서드를 통해 

key : value 쌍을 저장한다.

 

 

그리고 다시 onResume() 메서드에서 key : value 쌍을 가져와 변수에 할당한다. 이렇게 값을 온전히 임시로 저장하고 다시 가져올 수 있다.

 

 

 

"난 버튼이야"를 마구 클릭해서 숫자를 36이나 카운트 했다. 이제

다시 "ONPAUSE작동"버튼을 눌러서 투명한 창으로 액티비티 전환을 한 다음 백키를 통해 onResume() 메서드로 돌아왔을 때도 36이란 숫자가 그대로 있어야한다.

 

 

 

 

 

 

 

 

 

 

onResume()단계

 

처음 액티비티가 시작하고 나면 현재 onresume()단계에 있다.

 

전환된 화면

 

onPause()메서드 단계

 

ONPAUSE()이동 버튼을 누르면 위와같은 화면이 전화되고 단계는 onPuase()단계에 머무르고 있다.

 

 

 

onResume() 메서드로 복귀

 

다시 onResume() 단계로 돌아오고 count도 다시 복귀된다. 

 

 

5) onStop()

화면이 완전히 새로운 액티비티로 전환하여 기존의 화면이 보이지 않을 때, 호출된다. 이 단계에서도 마찬가지로 메모리를 최소화하는 작업을 하면 효율적이다. 이유 또한 강제로 프로세스가 죽어 모든 정보가 날라갈 수 있기 때문이다. 즉 위에서 onPause()단계에서 설명한 작업들을 그대로 onStop() 메서드 단계에서 실행하여 효율적으로 다뤄야한다. 또한 database에 저장할 타이밍을 적절하게 찾지 못했다면 이 단계에서 수행하는 것도 방법이다.

 

 

6) onDestroy()

액티비티가 완전히 소멸되기 전에 호출된다. 이 메서드를 호출하는 방법으론 두가지가 있다.

첫째, 사용자가 activity를 완전히 닫거나, 액티비티에서 finish()를 호출되서 activity가 종료되는 경우에 호출

둘째, 기기의 회전 또는 멀티 윈도우모드로 인해 시스템을 일시적으로 소멸시키는 경우이다 .

 

'android' 카테고리의 다른 글

newInstance()로 Fragment 생성해야하는 이유  (0) 2020.08.12
RecyclerView 2탄! item 클릭 시, 화면전환하기  (0) 2020.04.22
RecyclerView 사용해보기!( 1부 )  (1) 2020.04.17
Fragment LifeCycle  (4) 2020.03.03
Android Context  (6) 2020.02.24