6.3 Service
Service
` Service
◦ 안드로이드는 서비스에게 비활성 액티비티보다 높은 우선순위 부여
◦ 시스템이 리소스를 필요로 할 때 서비스가 종료될 가능성은 적음
◦ 서비스가 종료되었더라도 리소스가 충분해지면 즉시 재시작
◦ GUI 없이 실행
◦ Activity, Broadcast receiver와 같이 애플리케이션 프로세스의 메인 쓰레드 내에서 실행
x 좋은 반응성을 가지려면 시간이 많이 드는 처리(네트워크 조회 등)를 백그라운드 쓰레드로 옮겨야
` UI 없이 알림 Notification, Toast를 이용하여 정보 제공
` Toast
◦ 활성 애플리케이션의 포커스를 빼앗지 않은 채 사용자에게 정보를 표시하기 위해 사용되는 일 시적 성격의 non-modal 다이얼로그 박스 매커니즘
` Notification
◦ 보다 견고한 사용자 경보 메커니즘
◦ 사용자의 주의를 끄는 모든 동작(벨 울림, 진동, 불빛 깜박임)이 안드로이드에서는 Notification 을 통해 이용 가능
` Alarm
◦ 애플리케이션 수명 주기의 제어 바깥에서 정해진 시간에 Intent를 발생시키기 위한 메커니즘
2
Service 소개
` 두 가지 기능
◦ 백그라운드 작업 수행
◦ IPC(Inter-Process Communication)를 위한 원격접속 가능한 오브젝트를 만들어내는 것
` 백그라운드에서 실행되면서 Content Provider를 업데이트하고, Intent를 발생시키며, Notification을 만들어 냄
◦ 애플리케이션에 속한 Activity가 화면에 보이지 않거나, 비활성 상태가 되거나, 혹은 종료된 이후에도 정규 처리나 이벤트 처리를 수행하기 위한 방법
◦ Service는 GUI 없이 다른 Service, Activity, Broadcast Receiver를 포함한 다른 애플리케이션 컴 포넌트로부터 시작, 중지, 제어됨
` 특징
◦ 비활성 Activity나 눈에 보이지 않는 Activity보다 높은 우선순위 부여
◦ 런타임의 리소스 관리에 의해 종료될 가능성 낮음
◦ 포그라운드 서비스가 필요한 리소스를 얻지 못할 때만 종료
` 예
◦ 사용자 상호작용이 거의 드물거나 간헐적으로 필요한 애플리케이션 x MP3 플레이어, 스포츠 점수 모니터
◦ 안드로이드 내
x 위치 관리자, 미디어 컨트롤러, 알림 관리자
3
Service LifeCycle
4
Service 클래스
• 액티비티 구현 과정과 비슷하다.
• Service 클래스를 상속받아 새로운 클래스를 작성하는 작업이다.
1. onCreate() : 액티비티와 마찬가지로 서비스가 생성될 때 호출된다.
2. onStart() : 다른 프로세서에서 서비스를 수동으로 시작시킬 경우(Bindind), 또는 IPC 요청에 의해 시작될 경우
3. onDestroy() : 서시브가 종료될 때 호출된다.
Service 생성하기
public class MyService extends Service {
@Override
public void onCreate() {
// TODO: 서비스가 생성될 때 수행할 동작 }
@Override
public IBinder onBind(Intent intent) { // TODO: 서비스 바인딩 구현으로 대체한다.
return null;
}
// 서비스의 수명 내에서 여러 번 실행될 수 있다.
@Override
public void onStart(Intent intent, int startId) { // TODO: 서비스가 시작될 때 수행할 동작
}
@Override
public void onDestory() {
// TODO: 서비스가 종료될 때 수행할 동작 }
}
` 서비스 등록
` application 노드에 service 태그 포함
<service android:enabled="true"
android:name=".MyService"></service>
6
Service 시작, 제어, 그리고 상호작용
` Service 등록
` 만일 Service가 애플리케이션이 갖지 않은 권한을 요구하면 SecurityException 발생
• // 암시적으로 서비스를 시작시킨다.
• startService(new Intent(MyService.MY_ACTION));
• // 명시적으로 서비스를 시작시킨다.
• startServide(new Intent(this, MyService.class));
` Service 중지
• ComponentName service = startService(new Intent(this, BaseballWatch.class));
• // 서비스 이름을 이용해 서비스를 중단시킨다.
• stopService(new Intent(this, service.getClass()));
• // 명시적으로 서비스를 중단시킨다.
• try {
– Class serviceClass = Class.forName(service.getClassName());
– stopService(new Intent(this, serviceClass));
• } catch (ClassNotFoundException e) { }
7
Service 호출
9 서비스 기능을 호출하려면 해당 서비스에 대한 AIDL을 확보한 다음 AIDL에 포함된 특정 메소드를 일반 객체 메소드를 호출하듯이 호출하면 된다.
바인딩
• 서비스를 사용하려면 SeviceConnection 클래스를 상송받아 새로운 클래스를 구현해야 한다.
• ServiceConnection 클래스 : 특정 서비스를 대상으로 IPC 호출을 처리하는 서비스와의 연결을 의미한다.
1. onServiceConnected() : 액티비티가 원하는 서비스와 연결됐을 때 호출된다.
2. onServiceDisconnected() : 서비스와의 연결이 정상적으로 종료됐을 때 호출된다.
8
Service 호출
• 두 메소드는 연결하려는 서비스를 가리키는 ComponentName 인스턴스를 넘겨 받는다.
• onSeciveConnected() 메소드의 인자로 넘겨받는 Ibinder 인스턴스는 IPC를 호출할 수 있는 창구역 할을 한다.
9
Service LifeCycle
• 액티비티를 특정 서비스와 연결하려면 액티비티의 bindService() 메소르를 호출한다.
• bindSevice() 메소드는 위와 같이 세개의 인자를 넘겨 받는다.
1. 호출하려는 서비스를 가리키는 Intent
만약 직접 작성한 서비스를 호출한다면 해당하는 클래스 이름을 직접 지정한 인텐트를 사용할 수 있다.
2. ServiceConnection 인스턴스 3. 옵셥 설정 플래그
대부분의 경우에는 BIND_AUTO_CREATE값을 넘겨주는 정도로 충분하다.
BIND_AUTO_CREATE를 지정하면 해등 서비스가 아직 실행되지 않을 경우 서비스를 자동을 시작시킨다.
1 2 3
10
Service 호출과 해제
서비스 호출
• 서비스 인터페이스 객체가 준비를 마쳤다면
(mService = ((BgService.BgServiceBinder)binder).getService()), 인터페이스 객체를 통해 서비스 기능을 필요할 때마다 호출할 수 있따.
• 서비스 기능을 호출하려면 보통 두 가지 예외 처리를 해야한다.
1. DeadObjectException인데, DeadObjectException이 발생하면 서비스 연결이 비 정상적으로 끊겼 음을 의미한다.
Æ 서비스와 연결이 끊겼을 때의 절차를 진행하고, 필요하면 onServiceDisconnected() 메소드를 수동으로 호출해야 할 수도 있다.
2. RemoteException은 프로세스 간의 연결 과정에 뭔가 문제가 있음을 나태나는 범용예외이다.
Æ RemoteException이 발생해도 서비스와 연결을 새로 초기화하는 것이 좋다.
서비스 연결 해제
• IPC 호출을 모 두 사용한 다음 ServiceConnection 인스턴스를 인자로 넘기면서 unbindService()를 호출한다.
Æ onServiceDisConnected() 메소그다 호출되며, 서비스 인터페이스가 담겨있는 변수에 null을 설정해 더 이상 인터페이스를 사용하지 못하게 한다.
11
Service 호출과 해제
서비스 인터페이스 객체를 이용한 서비스 호출
서비스 연결 해제
12
백그라운드 작업자 쓰레드 이용하기
쓰레드를 사용해야할 때
– 애플리케이션이 좋은 반응성을 가지게 하기 위해
• 입력 이벤트에 대해 5초 이내, onReceive 핸들러를 10초 이내에 완료하지 않으 면 Application Unresponsive 메시지 나옴
– 느리고 시간이 많이 드는 모든 작업을 메인 애플리케이션 쓰레드에서 자식 쓰레드 로 옮긴다.
– Activity, Service, Broadcast Receiver 등을 포함한 모든 안드로이드 애플리케이션 컴 포넌트는 메인 애플리케이션 쓰레드 위에서 동작한다.
– 그러므로 어떤 한 컴포넌트 내에서 시간이 많이 드는 처리 Æ 다른 모든 컴포넌트 를 블록시킴
13
새로운 쓰레드 만들기
// 이 메쏘드는 메인 GUI 쓰레드에서 호출된다.
private void
mainProcessing() {
// 이는 시간이 많이 드는 작업을 자식 쓰레드로 옮긴다.
Thread thread = new Thread(null, doBackgroundThreadProcessing, "Background");
thread.start();
}
// 백그라운드 처리 메쏘드를 실행하는 Runnable
private
Runnable doBackgroundThreadProcessing = new Runnable() {
public void
run() {
backgroundThreadProcessing();
}
};
// 백그라운드에서 몇 가지 처리를 수행하는 메쏘드
private voidbackgroundThreadProcessing() {
[ ... 시간 소모적인 작업들 ... ] }
14
핸들러
` 응답없는 애플리케이션(ANR; Application Not Responding) 이벤트
◦ 5초 동안 사용자의 입력에 대해서 반응을 보이지 않는 것
◦ 강제 종료
◦ 메인 UI 쓰레드는 5초라는 지정된 시간 안에 무조건 반응해야 함
◦ 긴 계산시간이 요구되는 작업들은 반드시 별도의 쓰레드로 수행
` 핸들러
◦ 큐에 있는 작업들을 여러 쓰레드에서 처리시키고
◦ Message와 Runnable 객체를 이용하여 스케줄링 작업을 할 수 있게 함
◦ 별도의 쓰레드에서 작업한 결과는 핸들러가 있는 메인 UI 쓰레드로 리턴되어 클래스들과 함께 수행
◦ 핸들러가 생성되면 Looper와 함께 수행
◦ 핸들러는 현재 수행중인 쓰레드, 보통은 메인 UI 쓰레드와 자동으로 연결되기 때문
◦ handleMessage(Message m) 메쏘드도 함께 만들어주어야 메시지 처리 가능
◦ Message는 ‘send’로, runnable 객체는 ‘post’로 전달함
15
핸들러 사용법 및 HandlerThread, Looper, 큐의 관계
MainUIThread
(HandlerThread) Handler myHandler = new Handler() {
public void handleMessage(Message m) { updateUIHere();
} };
new Thread() {
public void run() { doStuff();
Message m = myHandler.obtainMessage();
Bundle b = new Bundle();
b.putString(“key”, “value”);
m.setData(b);
myHandler.sendMessage(m);
}
}.start();
Looper
MessageQueue 다른 쓰레드
16
장시간 Service 프로그램에 대한 주의사항
• 시스템에 부하를 줄 수 있으므로 장시간 동안 서비스를 해야 하는 프로그램 은 추천하지 않는다.
• 만약 사용자가 더 사용할 가능성이 없는 경우라면 프로그램을 종료할 때 함 께 종료하는 것이 바람직함
• 필요하다면 사용자에게 옵션으로 제공하여 선택할 수 있게 만드는 것이 좋 음
17
GUI 작업을 위한 쓰레드 동기화
// 메인 쓰레드에서 핸들러를 초기화한다.
private Handler handler = new Handler();
private void mainProcessing() {
// 이는 시간이 많이 드는 작업을 자식 쓰레드로 옮긴다.
Thread thread = new Thread(null,
doBackgroundThreadProcessing, "Background");
thread.start();
}
// 백그라운드 처리 메쏘드를 실행하는 Runnable
private Runnable doBackgroundThreadProcessing = new Runnable() { public void run() {
backgroundThreadProcessing();
} };
// 백그라운드에서 몇 가지 처리를 수행하는 메쏘드 private void backgroundThreadProcessing() {
[ ... 시간 소모적인 작업들 ... ] handler.post(doUpdateGUI);
}
// GUI 업데이트 메쏘드를 실행하는 Runnable
private Runnable doUpdateGUI = new Runnable { public void run() {
updateGUI();
} };
private void updateGUI() {
[ ... 다이얼로그를 오픈하거나 GUI 요소를 수정할 수 있다 ... ] }
18
실습 하기 - (1)
서비스를 이용한 음악 재생하기
19