반응형

태스크란? (Task, Activity Stack)
어피니티란? (Android Affinity)
플래그란? (Android Flag)




안드로이드 태스크란? (Android Task, Activity Stack)

- Task는 어플리케이션에서 실행되는 액티비티를 보관하고 관리하며 Stack형태의 연속된 Activity로 이루어진다

- 선입후출(First In Last Out)형태로 나중에 적재된 액티비티일 수록 가장 먼저 사용된다 
만약 1페이지>2페이지>3페이지 순으로 액티비티를 이동했을때 실행순서대로 Task에 push해 놓았다가
back버튼을 누르면 3페이지>2페이지>1페이지순으로 Task에서 pop시켜 되돌아 간다고 생각하면 된다

- 서로 다른 어플리케이션간의 이동에도 Task를 이용해 사용자 경험(UX)를 유지시켜 준다

- 최초적재 액티비티는 Root Activity 라고 하며 어플리케이션 런처로부터 시작된다

- 마지막으로 적재되는 액티비티는 Top Activity 라고 하며 현재 화면에 활성화 되어있는 액티비티를 말한다

- Task내에는 서로 다른 어플리케이션의 액티비티들이 포함될 수 있어 어플리케이션에 경계없이 하나의 어플리케이션인것 처럼 보이게 해준다

- Task의 Stack내에 존재하는 액티비티들은 모두 묶여서 background와 foreground로 함께 이동한다. 홈버튼 클릭(task interrupt => background 이동), 홈버튼 롱클릭(recent task => foreground 이동)

- Flag를 사용하여 Task내 액티비티의 흐름을 제어할 수 있다


어피니티란? (Android Affinity)

- 어플리케이션 내의 액티비티들은 하나의 어피니티를(affinity:친화력) 가지고 있다

- AndroidManifest 에서 <activity> 요소의 taskAffinity 속성을 사용해 개별 affinity가 지정 가능하다

- FLAG_ACTIVITY_NEW_TASK 플래그를 가진 인텐트 객체로 부터 호출된 allowTaskReparenting 
속성을 True로 가지고 있는 액티비티에 한해 affinity 가 동작한다

- 위 조건이 만족한 상황에서 시작된 액티비티는 자신과 동일한 어피니티를 갖는 태스크가 있을경우 해당 태스크로 이동한다

- 즉, [b]어피니티를 가진 A액티비티가 호출되어 해당 태스크에 속해있을때 [b]어피니티를 가진 태스크가 호출되면 A액티비티는 [b]어피니티를 가진 태스크로 이동한다

- 어피니티에 의해 태스크가 이동된 후에 back버튼으로 반환시 원래 해당하던 태스크로 돌아간다

- 하나의 어플리케이션내에서 하나 이상의 기능을 갖는 어플리케이션이 존재할경우 각 액티비티별로 
다른 어피니티를 지정해 관리할 수 있다


플래그란? (Android Flag)

- AndroidManifest 에서 플래그를 사용할때에는 <activity> 요소의 launchMode 속성을 사용하며
launchMode에서 사용가능한 속성은 다음과 같이 4가지만 가능하다

standard: 
스택중 어느곳에나 위치 가능하며 여러개의 인스턴스가 생성가능하다

singleTop: 
스택중 어느곳에나 위치 가능하며 여러개의 인스턴스가 생성가능하고 호출한 activity와 현재
최상위 activity가(top activity) 동일한 경우 최상위 activity가 재사용 된다(기존 최상위 activity는 pop)

singleTask: 
루트 액티비티로만 존재하며 하나의 인스턴스만 생성가능하다(타 task에서 동일 activity 사용불가)
다른 액티비티 실행시 동일 Task내에서 실행이 가능하다

singleInstance: 루트 액티비티로만 존재하며 하나의 인스턴스만 생성가능하고 태스크내에 해당
액티비티 하나만 속할 수 있어
 다른 액티비티를 실행시키면 새로운 Task가 생성되어
(FLAG_ACTIVITY_NEW_TASK와 동일) 그 Task내에 포함된다


- 소스코드에서 플래그를 사용하고 싶을때에는 Intent에 addFlags() 또는 setFlags() 메소드를 사용한다

FLAG_ACTIVITY_NEW_TASK: 
동일 affinity의 task가 있으면 그곳에 실행되고 아니면 새로운 task를 실행

FLAG_ACTIVITY_SINGLE_TOP: 
상단 singleTop과 같으며, 실행시 재사용 액티비티의 실행은 onPause(), onNewIntent(), onResume()
순으로 호출된다
☞ [B]를 single top설정: [A][B] 상태에서 [B] 호출시 => [A][재사용된B]
☞ [B]를 single top설정: [B][A] 상태에서 [B] 호출시 => [B][A][B]

FLAG_ACTIVITY_NO_HISTORY:
해당 액티비티는 재활성화시(back키를 눌러 다시 활성화될때) pop 된다
☞ [B]를 no history설정: [A][B][A] 상태에서 back키 사용시 [A]가 pop 되고 [B] 역시 
no history에 의해 pop => [A]

FLAG_ACTIVITY_REORDER_TO_FRONT:
activity 호출시 이미 같은 activity가 task내에 있으면 같은 activity는 pop 시키고 해당 activity가 push 된다
☞ [A]를 reorder to front설정: [A][B] 상태에서 [A] 호출시 같은 activity인 [A]가 pop되고 => [B][A]

FLAG_ACTIVITY_CLEAR_TOP:
해당 task에 있는 모든 activity를 pop 시키고 해당 activity가 root activity로 task에 push된다
☞ [A]를 clear top설정: [A][B] 상태에서 [A] 호출시 모두 pop되고 => [A]
단, 해당 플래그는 액티비티를 모두 onDestroy() 시킨 후 새롭게 onCreate() 시키기 때문에 [A]를
유지하려면 FLAG_ACTIVITY_SINGLE_TOP 플래그와 함께 사용하면 된다

http://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_BROUGHT_TO_FRONT


Clear Task

- Task를 오랫동안 사용하지 않고 방치해 두면 시스템은 Root Activity를 제외한 모든 액티비티를 Clear 시킨다
- 이러한 동작은 Activity의 속성을 수정하여 제어할 수 있다

alwaysRetainTaskState:
Task의 Root Activity에 true로 설정되어 있다면 상단에 언급되었던 동작은 발생하지 않으며 Task는
오랜 시간 이후에도 Stack에 있는 모든 Activity를 유지한다

clearTaskOnLaunch:
이 속성이 true로 설정되어 있으면 alwaysRetainTaskState 와 정반대로 사용자가 Task를 떠났다가
다시 돌아올 때마다 항상 Stack은 Root Activity로 정리된다

finishOnTaskLaunch:
이 속성은 clearTaskOnLaunch와 유사하지만 전체 Task가 아닌 단일 Activity에서 동작한다
그리고 그것은 Root Activity를 포함한 어떤 Activity가 사라지는 원인이 될 수도 있다
true로 설정되어 있을 때, Activity는 현재 Session 동안 Task의 일부만 유지한다
만일 사용자가 해당 Task를 벗어났다가 다시 돌아오면 더이상 존재하지 않는다



반응형
,
반응형

안드로이드의 Process

타 운영체제와 마찬가지로, 실행가능한 프로그램 데이터가 메모리로 로드되어 실행된 것을 프로세스라고 한다. 안드로이드는 리눅스 기반의 OS이므로, 리눅스의 프로세스처럼 각각 ID가 부여되며, 다른 프로세스와 철저히 격리되어 실행된다.

Process의 구등

안드로이드는 앱의 컴포넌트(엑티비티, 서비스, 리시버, 프로바이더)를 실행하는 시점에서, 그 컴포넌트가 메모리로 로드되고, 컴포넌트가 속한 앱의 프로세스가 구동된다.
Note : 앱의 프로세스가 새로 구동될 때마다, 시작점은 Application의 onCreate()메서드이다.

Process 변경

컴포넌트는 기본적으로 앱의 프로세스에 속하지만, 소속 프로세스를 변경할 수도 있다.
메니페스트 파일에서 컴포넌트를 선언할 때, android:process 필드를 지정하면, 이 컴포넌트는 앱의 프로세스와는 별개로, 다른 독립된 프로세스에서 실행된다.
Note : 별도의 프로세스에서 동작하더라도, Application의 onCreate()메서드는 호출된다.(왜그럴까......??)

안드로이드의 Task

앱을 실행하게 되면, 그 앱은 필요한 컴포넌트들을 호출하게 된다. 각 앱마다 현재 사용하고 있는 컴포넌트들을 그룹화하여 관리하는 것이 Task이다. 여기서의 컴포넌트는 해당 앱에 속한 컴포넌트 일수도 있고, 다른 앱에 속한 컴포넌트 일수도 있다.

컴포넌트 교차 생성

안드로이드의 독특한 특징으로, 다른 앱에 속한 컴포넌트를 호출하여 사용할 수 있다. 이렇게 호출된 컴포넌트는 현재 실행되고 있는 앱의 Task에 속하게 된다. 하지만, 호출된 컴포넌트가 메모리에 로드되면, 그 컴포넌트의 원래 프로세스가 구동되며, 컴포넌트가 실행되면서 필요한 권한설정은 원래 앱이 획득한 권한설정을 따르게 된다.
  • ex) 메모앱에서 기본 카메라의 엑티비티를 호출하는 경우
    • 기본 카메라의 엑티비티는 메모앱의 Task로 묶이게 된다.
    • 메모앱이 기본 카메라 엑티비티를 호출하는 시점에, 기본 카메라 앱의 프로세스가 구동된다. 즉, 메모앱의 프로세스와 기본 카메라 앱의 프로세스가 동시에 실행중인 상황이 된다.
    • 기본 카메라 엑티비티가 사용하고자 하는 권한(카메라 접근, 외부저장소 저장 등)은 메모앱의 권한설정이 아닌, 기본 카메라 앱의 권한설정을 따르게 된다. 따라서, 메모앱은 사진관련 권한이 없어도, 기본 카메라 앱에 권한이 있으면 문제없이 이용할 수 있고 반대로, 메모앱이 사진관련 권한이 있어도, 기본 카메라 앱에 권한이 없으면 기능을 이용할 수 없다.

엑티비티 스택

Task는 엑티비티의 순서를 관리하기 위해 별도로 스택을 유지하여 엑티비티를 저장한다. 즉, Task가 지워지면, 엑티비티의 순서도 지워지게 된다.

Task 변경

다른 컴포넌트들에 비해, 엑티비티는 메니페스트에서 <activity>태그의 android:launchMode 필드를 주거나, 엑티비티를 실행할 인텐트에 플래그 값을 추가하여 Task를 변경할 수 있다.(변경이라고는 해도 Task간 이동은 불가능하다.)


반응형
,
반응형

Broadcast Receiver 란?

  • 안드로이드 4대 컴포넌트 중 1개다.

  • 각종 앱에서 발생하는 방송(이벤트)을 캐치 후 리시버로 처리할 수 있도록 해준다.

  • 1. 방송하기 -> 2. 수신하기(방송에 대한 처리), 두 개가 하나의 사이클로 동작된다.



리시버의 종류


정적 리시버

  • 한번 등록되면 해제할 수 없다.

  • 메니페스트에 리시버를 등록하는 방식으로 정적리시버를 등록한다.

  • 해당 앱이 설치될때 자동으로 등록된다.


동적 리시버

  • 등록과 해제가 자유롭다.

  • 메니페스트에 등록하지않고 소스상에 등록을 한다.




리시버의 동작 제한(인텐트 플래그를 통한)


FLAG_EXCLUDE_STOPPED_PACKAGES  

  • 앱이 한번이라도 실행됬을때만 리시버가 동작할 수 있도록 해준다.

  • API 12 이후로는 이 플래그는 기본으로 설정된다.


FLAG_INCLUDE_STOPPED_PACKAGES

  •  한번도 실해되지 않은 앱이라도 리시버가 동작하게 해준다.


FLAG_RECEIVER_REGISTERD_ONLY

  • 오직 동적리시버만 방송받을 수 있도록 해준다.


FLAG_RECEIVER_REPLACE_PENDING

  • 동일한 액션으로 중복해서 방송하는 경우 중복된 방송을 제거해준다.



리시버 동작시간 제한


리시버에서도 액티비티와 마찬가지로 작업시간이 제한되어있다. (메인스레드에서 동작하므로)


백그라운드 리시버 : 60초

포그라운드 리시버: 10초



리시버 호출 및 우선순위

  • 정적리시버는 절대 동시에 실행되지 않고 한개씩 처리한다.

  • 정적리시버는 앱이 먼저 설치된 우선순위로 실행된다.

  • 동적리시버는 동시에 실행된다.(우선순위가 중요하지않다.)

  • 동적리시버는 리시버가 작성된 컴포넌트가 종료되면 동작하지 않는다.(사실 onDestroy()함수에 unregister(receiver)를 통해서 리시버를 해제하지 않으면 동작하는데 그러면 메모리 누수가 발행하므로 꼭 해준다)

  • 방송할때 인텐트필터의 setPriority(1)함수로 우선순위를 조작할 수 있다. (클수록 우선, 동적리시버는 우선순위가 중요하지않음)

  • 정적리시버의 우선순위는 메니페스트의 인텐트필터요소에서만 설정가능하다. ( <intent-filter android:priority="1"> .. ) 

  • sendBroadcast()대신 sendOrderBroadcast()를 사용하면 동적리시버에서도 우선순위를 적용해서 처리할 수 있다.

  • setPackage()함수로 원하는 패키지의 리시버만 동작하도록 방송할 수 있다.




정적리시버 등록 및 사용 예


1. TestReceiver.java 클래스 작성

public class TestReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
Log.i("리시버알림","라이트 온");
Toast.makeText(context, "Light On !!", Toast.LENGTH_SHORT).show();
}
}

2. 메니페스트에 TestReceiver 등록

<?xml version="1.0" encoding="utf-8"?>
<manifest>

<application>

...

<receiver android:name=".TestReceiver">
<intent-filter>
<action android:name="com.test.action.TEST"/>
<action android:name="android.intent.action.SCREEN_ON"/>
</intent-filter>
</receiver>

</application>

</manifest>

3. 액티비티에서 호출 

@Override
protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Intent intent = new Intent();
intent.setAction("test.com.action.TEST");
sendBroadcast(intent);
}

4. 동작설명

4-1. 위의 3번의 액티비티 화면의 앱을 켜면 방송(Broadcast)을 특정액션(test.com.action.TEST)으로 한다.

4-2. 메니페스트에 등록한 정적리시버가 test.com.action.TEST의 액션을 포함하고 있으므로 4-1에서 방송을 리시버가 캐치해서 실행한다.

4-3. Light On !! 이란 토스트팝업이 뜬다.

4-4. 또한 2번의 메니페스트에 android.intent.action.SCREEN_ON 액션도 설정했으므로 휴대폰 화면을 껐다 켜도 이 리시버가 동작한다.



동적리시버 등록 및 사용 예


동적리시버는 메니페스트에 리시버를 등록해놓지 않는다.


1. 동적리시버 생성 및 등록


BroadcastReceiver receiver = null;

@Override
protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// 인텐트 필터 설정
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("test.com.action.TEST");

// 동적리시버 생성
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Light On !!", Toast.LENGTH_SHORT).show();
}
};
// 위에서 설정한 인텐트필터+리시버정보로 리시버 등록
registerReceiver(receiver, intentFilter);

} 

2. 동적으로 등록한 리시버 호출


Intent intent = new Intent();
intent.setAction("test.com.action.TEST");
sendBroadcast(intent);
 

동작은 정적리시버 예제와 동일하게 동작한다.



출처: http://thereclub.tistory.com/15 [아메리카노 공방]

반응형
,