본문 바로가기

Programming/Android

[Android] #7 Activity & Task

Activity는 일종의 JAVA의 Thread와 비슷하다. 각기 따로 수행이 되면서도 Activity간의 호출과 data 전달이 가능하다. 이는 Intent를 통하여 구현이 되는데

Intent는 후에 살펴볼 예정이다.


Activity & Task

Activity에는 생명 주기가 존재한다. Android 런타임이 각 application의 process와 그 안에 있는 activity를 관리한다. 각 activity의 상태는 현재 실행 중인 모든 activity의 Last in first out 방식인 Activity Stack에서 그가 어디에 있느냐에 따라서 결정이 된다. 새로운 activity가 시작되면 현재 foreground screen이 activity stack의 맨 꼭 대기로 옮겨진다. 만약 이때 foreground Activity가 종료될 경우에는 stack에 있는 다음 Activity가 위로 올라와서 활성화 상태가 된다. Application의 우선 순위는 Application이 가진 Activity가운데 가장 높은 우선 순위를 가진 것에 영향을 많이 받는데, Android memory manager는 자원 해제를 위해 어느것을 선택을 해야 하는 지를 결정을 할 때 이 Stack을 이용을 한다.

Activity State

A. Active

Activity가 stack의 맨 위에 있을 경우, 화면에 보이고 포커스를 가진다. 이때 리소스를 확보 하도록 stack가장 아래쪽의 activity들을 종료시킨다.

B. Paused

일시중지는 화면에 보이지만 포커스를 가지지 않은 경우이다. 이 경우는 투명한 activity가 그 앞에 활성화되는 경우도 해당이 된다.

일시 중지 상태가 되는 경우 activity는 활성 상태인 것 같지만 사용자 입력등과 같은 동작을 하지 않는다. 

C. Stopped

Activity가 화면에 보이지 않는 경우에 중지가 된다. 이 activity는 모든 상태 및 멤버 정보를 가지고 메모리에 남겠지만 메모리

관리자가 자원 해제를 하는 경우 1순위로 해제가 될 것이다.

D. Inactive

Activity는 종료되고 난 이후와 띄워지기 이전 비활성 상태로 있는다. 메모리 관리자는 이것을 해제하고 다시 사용할려면 다시

시작해야한다.



Activity Life Cycle

 

다음 코드들은 activity에서 사용할 수 있는 상태 변화 메서드 핸들러를 나타낸다. 그냥 간단하게 알아본다.

package com.android.myActivity; 

import android.app.Activity; 

import android.os.Bundle; 

public class MyActivity extends Activity {
	/** Called when the activity is first created. */ 
	@Override 
		
	public void onCreate(Bundle savedInstanceState) { 
		super.onCreate(savedInstanceState); 
		setContentView(R.layout.main); 
		/// initialize activity 
	} 
	// onCreate가 호출이 된 후 GUI 상태 복구를 위해서 사용을 하는 함수 

	public void onRestoreInstanceState(Bundle savedInstanceState) { 

	super.onRestoreInstanceState(savedInstanceState); 

	// savedInstaceState로부터 GUI 상태를 복구를 한다.
	// 인수로 받는 Bundle은 onCreate에도 전달된다. 

	} 

	/// visible lifetime으로 가기 전 activity 처리를 위해서 호출이 된다. 

	public void onRestart(){ 

		super.onRestart(); 

		// activity가 이미 화면에 보이고 
		// 여기서 변경된 것들만 읽어들인다. 

	} 

	/// visible lifetime start시에 호출된다. 

	public void onStart(){ 

		super.onStart(); 

		// 여기서는 activity가 화면에 보이므로 
		// 필요한 GUI 변경 사항을 적용한다. 

	} 

	/// active lifetime시에 호출이 된다. 

	public void onResume(){ 

		super.onResume(); 

		/// 일시 중지된 모든 GUI update나 thread 
		/// activity에 의해서 필요하지만 activity가 비활성화 
		/// 되면서 일시 중단된 것들을 처리를 다시 시작을 할 때 

	} 

	/// GUI 상태를 저장을 하기 위해서 호출이된다. 

	public void onSaveInstanceState(Bundle savedInstanceState){ 

	/// GUI state를 savedInstanceState에 저장한다. 
	/// 프로세스가 중료되거나 재시작될 경우 
	/// 이 번들이 onCreate에 전달이 되서 
	/// 그 시점부터 다시 시작이 될 것이다. 

		super.onSaveInstanceState(savedInstanceState); 

	} 

	/// active lefetime 끝에서 호출된다. 

	public void onPuase() { 

		super.onPause(); 

		/// activity가 포그라운드 상태가 아닐 경우 
		/// 다시 update 되거나 필요가 없는 GUI및 Thread 
		/// 프로세서 점유율이 높이는 처리는 일시 중지한다 

	} 

	/// visible lifetime 끝에서 호출 

	public void onStop() { 

		super.onStop(); 

		/// 남아있는 GUI 업데이트나 쓰레드 
		/// activity가 화면에 보이지 않을 때 필요치 않은 처리를 일시 중단을 한다.
		/// 이 메서드가 호출이 되고 난 뒤에는 프로세스가 종료될 가능성이 있으므로
		/// 바뀐 모든 내용과 상태 변화를 지속시킨다. 

	} 

	/// full lifetime의 맨 마지막에 호출이 된다. 

	public void onDestroy(){ 

		super.onDestroy(); 

		/// 쓰레드 종료 및 Close DB connect 
		/// 모든 리소스 해제 

	} 

}



간단하게 예를 들어보자.

Activity_1, Activity_2가 존재한다고 가정하자.

1) Activity_1 구동시

   1_onCreate

   1_onResume

2) Activity_1 ->Activity_2 구동시

   1_onPause

   2_onCreate

   2_onResume

   Display Activity_2

   1_onStop

3) 2번 상황에서 back 했을 경우

   2_onPause

   1_onRestart

   1_onResume

   2_onStop

   2_onDestroy

4) 2번 상황에서 home 키 눌렀을 경우

   2_onPause

   2_onStop

5) 1번 상황에서 back 했을 때

   1_onPause

   1_onStop

   1_onDestroy

6) 4번 상황에서 testapp 실행 했을 때

   2_onRestart

   2_onResume



Home Key와 Back Key의 차이

여기서 Home key와 Back key의 차이점이 궁금해 진다. 일반적으로 Application을 실행하면 해당 Application의 Root Activity가 먼저 실행

된다. 그 상태에서 Back key나 HOME과 같은 Activity 전환에 대한 키를 누를 수가 있다. Android에서는 이런 동작에 따라 Activity와 Task에

대한 동작이 달라진다.

A. Home Activity에서 Application을 실행

Home에서 Application을 실행 할 경우 Application의 Root Activity는 다음과 같은 상태가 된다.

Home Activity : Foreground -> Background

App Activity : <Create> -> Foreground

B. Back Key를 눌러 Home으로 이동하는 경우

만약 Back key를 누를 경우 Back Activity는 Home Activity이므로 현재 Activity를 제거하고(onDestroy() 실행) Home으로 되돌아간다.

Back key를 누르더라도 Activity가 Destroy되지 않는 예외의 경우도 존재하는데 Audio player처럼 Background실행이 필요한 경우

Service형태로 처리하는 경우다.

Home Activity : Background -> Foreground

App Activity : Foreground -> <Destroy>

C. Home key를 눌러 Home으로 이동하는 경우

Activity를 실행 중 Home key를 누르면 무조건 Home Activity로 되돌아 가는 것을 확인 할 수 있다. 이럴 경우 실행 중이던 Activity는

잠시 Background상태가 되지만 제거 되지는 않는다.

Home Activity : Foreground -> Background

App Activity : Background -> <Running> -> Foreground

이때 만약, 새로운 Application을 실행할 경우 새로운 Task가 활성화 되는 것으로 기존 Application과 동시에 실행되는 모습이 된다

Home Activity : Foreground -> Background

App Activity : Background -> <Running> -> Foreground

New Activity: <Create> -> Foreground in Task #2


Activity 재사용하기

Activity A가 다른 Application에 있는 Activity B를 시작할 때, Activity B는 재사용(reused) 되었다라고 한다. 이러한 경우는 보통 Activity A는

여건이 없고 Activity B에는 있을 때 발생한다.

A. Contacts에서 Gallery를 재사용하여 사진얻기

reuseed의 좋은 예로 Gallery Activity가 있다. Contacts Activity는 주소록의 사진 항목을 가지고 있찌만, 사진이 보관되어 지는

곳은 보통 Gallery이다. 그렇기에 Contacts에서 사진을 가져오기 위해 Gallery Activity를 재사용 할 수 있다.

Application을 디자인할 때 다른 Application에 있는 Activity를 어떻게 reused할 지 생각하는 것과 자신이 만든 Activity를 다른

Application에게 어떻게 reused하도록 할지를 염두해 두는 것은 매우 중요하다. 만약 Activity를 추가 할 때 기존에 있던 Activity와

동일한 Intent filter를 적용한다면, 시스템은 사용자에게 이 Activity들 중 어떤 것을 선택 할 것인지 알려준다.

B. Gallery에서 Messaging 재사용하여 사진 공유하기

공유 역시 한 Application이 다른 Application으로 부터 온 Activity를 reused하는 또 다른 좋은 예가 될 수 있다.


Activity 대체

위에서 Activity의 Intent filter를 기존 Activity와 동일하게 설정 할 경우 user가 어떤 Activity를 이용할지 선택할 수 있다고 언급했었다. 이를

Activity 대체라고 한다.

이것은 Activity A가 다른 application에 있는 Activity B를 대체하는 경우이다. 이런 상황은 보통 Activity A가 Activity B의 기능보다 더 나은

기능을 제공하기 때문에 발생한다. 다시 말해서, A가 B를 대체할 만큼 A와 B가 동등하다는 것이다. 이 경우 A와 B가 꽤 많이 다른 Activity

들이며 서로가 다른 것들을 가지고 있을 때 Activity의 reused와 두드러지게 대비된다.



Multi Tasking

Activity가 실행 중 HOME key를 누르면 새로운 Task로 인식되며 Multi Tasking이 시작된다.

1 step - user가 View map Activity를 실행하고도 지도 위치를 검색한다. 네트워크가 느리다고 한다면 Maps는 지도를 그리는데 시간이 오래걸린다.

2 step - user는 기다리는 동안에 뭔가를 하고 싶어 Home키를 눌러 maps의 네트워킹 접속을 방해하지 않고 Background에서 loading이 계속되도록 한다.

Activity가 Background로 옮겨지면 Activity life cycle에 따라 onStop() method가 호출되므로 Activity를 작성 할 때 계속 할 것인지 아니면 잠시 멈출 것인지 결정 할 수 있다. 네트워크로부터 데이터를 다운로드하는 Activity들에 있어서 downloading을 계속 하도록 두는 것은 중요하며 이로써 multi-task를 가능하게 한다.

3 step - map Activity는 이제 Background에서 실행되고 있고, Home은 Foreground로 실행되고 있다. 사용자가 Calendar Activity를 실행하면 Foreground가 되고, 사용자 focus를 가지며, 오늘 날짜의 달력이 보여진다.



4 step - 사용자가 HOME을 눌러 maps를 다시 실행하면 지도 데이터가 완전하게 load되어진 모습이 보여진다.
 



두 개의 시작점으로 실행하기

모든 application은 적어도 하나 이상의 시작점(entry point)를 가져야 한다. 시작점은 user혹은 system이 Application 내부에 있는 Activity에

접근하기 위한 방법이다. Home에 있는 Application launcher에 있는 각각의 icon이 Application의 시작점을 나타내고 있는 것이다. Application은 다른 Application에서 실행 될 수도 있다. 또한 각각의 Activity는 Application에 잠재되어 있는 시작점이다.



Task 전환

이번에는 user가 두 개의 Task를 전환하는 과정을 확인해보자. 예를 들어 사용자가 SMS를 작성하고 이미지를 첨부하지만 끝내기 전에 잠깐 달력을 본다고 하자. 그리고 첨부된 사진이나 SMS를 남겼던 곳으로 되돌아 온다고 하자.

A. Task 시작하기

SMS와 사진을 첨부하기 위해서는

HOME > Messaging > New Message > Menu > Attach > Pictures 의 마지막 단계는 사진을 선택하기 위해 Picture Gallery가 실행된다. Picture Gallery는 별도의 Application이다.

사진을 선택하기 전에 잠깐 멈춰서 별도의 Task에서 Calendar를 보려 한다. 현재 Activity가 Calendar로 바로 가는 버튼이 없으므로 Home에서 시작해야 한다.

 

B. 두 번째 Task 시작하기

Home > Calendar를 선택하여 Calendar event를 본다. Application Launcher는 각각의 Application이 실행될 때 마다 새로운 Task로 실행을 하기 때문에 Calendar는 Home에서 새로운 Task로 실행이 된다.

 


C. 첫 번째 Task로 전환하여 마무리 하기

Calendar를 다 보고 난 후 root Activity를 다시 시작하여 사진을 첨부하는 곳으로 되돌아 갈 수 있다.

Home > Message 선택, 이것은 Message로 가는 것이 아니라 떠나기전 있던 곳인 Picture Gallery로 바로 진입한다. 이제 메시지에 첨부할 사진을 선택하고, SMS를 보내면 처음 시작했던 Task를 마치게 되는것이다.