ch16 서비스

Report
서비스
안드로이드 프로그래밍 정복(Android Programming Complete
Guide)
Contents
 학습목표
 서비스는 백그라운드에서 실행되는 프로세스이다.
 사용자와 상호작용 없이 배경에서 지속적으로 실행되는 데몬 제작 방법
에 대해 실습하고 데몬이 사용자에게 알림을 보낼 수 있는 통지와 알람
등의 기술을 익힌다.
 내용
 통지
 BR
 서비스
2/37
1. 통지
 백그라운드 알림
 통지(Notification) : 백그라운드 프로세스가 사용자와 통신할 수 있는 좀 더 확실한 방법
 통지는 최초 잠깐 보이지만 토스트와 달리 사용자가 확인하기 전에는 아이콘이 계속 표
시되며, 소리나 진동, 불빛 같은 좀 더 적극적인 방법으로 사용자에게 신호를 보낸다.
 상태란을 아래로 드래그하여 확장하거나 Home 화면 메뉴에서 Notification 항목을 선택
하면 통지에 대한 상세한 정보가 출력된다.
3/37
1. 통지
 백그라운드 알림
 통지를 출력하려면 통지 관리자(NotificationManager)와 통지 객체(Notification) 둘을 사
용해야 하는데 미리 준비해야 할 것이 많아 번거롭다.
 통지 객체의 생성자는 다음과 같다.
• Notification(int icon, CharSequence tickerText, long when)
 Icon은 상태란에 표시될 작은 그림, tickerText는 통지 영역에 아이콘이 처음 나타날때
잠시 출력될 짧은 문자열이며, when은 통지가 발생한 시간을 지정하여
System.currentTimeMillis 메서드로 구한 현재 시간을 지정하는 것이 보통이다.
 생성자로 객체를 생성한 후에도 icon, tickerText, when 등의 필드에 값을 직접 대입하여
통지의 내용을 변경할 수 있다.
 실행 중에도 언제든지 값들은 변경 가능하다.
4/37
1. 통지
 백그라운드 알림
 필드들에 값을 대입함으로써 통지를 전달하는 방법을 다음과 같이 상세하게 지정한다.
필드
설 명
sumber
통지 아이콘에 겹쳐서 출력될 숫자를 지정한다. 예를 들어 새로운 메시지가 도착했다는 통
지라면 메시지의 개수를 같이 표시할 수 있다. 0이나 음수를 지정하면 숫자가 표시되지 않
는다.
sound
통지와 함께 출력할 소리를 Uri 객체로 지정한다
vibrate
진동 방식을 지정한다. 진동할 시간과 멈출 시간을 배열로 전달함으로써 진동의 패턴을 지
정한다.
ledARGB
불빛의 색상을 지정한다. 장비에 장착된 LED의 능력에 따라 표현 가능한 색상은 조금 달
라질 수도 있다.
ledOnMs, ledOffMs
LED를 결 시간과 끌 시간을 1/1000초 단위로 지정한다. 이 두 값은 LED의 점멸 주기를
결정한다. 정확하지는 않지만 장비는 가급적 근접한 시간을 지킨다.
defaults
디폴트로 취할 통지 전달 방식을 지정한다
flags
통지의 동작 방식을 지정한다
5/37
1. 통지
 백그라운드 알림
 시스템은 디폴트 소리와 진동 기능을 제공하는데 defaults 필드에 어떤 기능을 시스템이
제공하는 디폴트로 사용할 것인가를 다음과 같이 지정한다.
플래그
설 명
DEFAULT_SOUND
소리를 발생시킨다.
DEFAULT_VIBRATE
진동을 발생시킨다.
DEFAULT_LIGHTS
불빛을 깜박거린다.
DEFAULT_ALL
위 세가지 동작을 모두 수행한다.
 flag 필드에는 통지의 동작 및 관리방법을 다음과 같이 지정한다.
플래그
설명
FLAG_AUTO_CANCEL
사용자가 아이콘을 탭하면 자동으로 통지를 취소한다
FLAG_INSISTENT
취소하거나 상태란을 확장하기 전까지 소리를 계속 발생시킨다
FLAG_NO_CLEAR
사용자가 clear all을 선택할 때 취소한다.
FLAG_ONGOING_EVENT
계속 진행중인 이벤트를 참조한다.
FLAG_ONLY_ALERT_ONCE
이전에 취소된 통지라도 매번 소리와 진동을 발생시킨다.
FLAG_SHOW_LIGHTS
LEB 불빛을 출력한다.
6/37
1. 통지
 백그라운드 알림
 속성을 설정한 후 확장 상태란에 표시될 정보와 사용자가 통지 객체를 선택했을 때의 반
응을 다음 메서드로 지정한다.
• void setLatestEventInfo (Context context, CharSequence contentTitle, CharSequence contentText,
PendingIntent contentIntent)
 확장 상태란 : 타이틀 영역보다 넒으므로 조금 더 길고 상세한 메시지를 전달할 수 있다.
 PendingIntent 클래스는 인텐트를 래핑하며 다른 응용 프로그램으로 전달하여 실행 권한
을 준다는 점에서 보통의 인텐트와 다르다.
 Intent는 사용자가 통지 객체를 탭했을 때의 동작을 지정하며, 주로 액티비티를 띄우는
데 인텐트에는 FLAG_ACTIVITY_NEW_TASK 플래그를 지정해야 한다.
 통지 관리자는 시스템이 제공하는 서비스이므로 객체를 직접 생성할 필요 없이 다음 호
출문으로 구한다.
• getSystemService(NOTIFICATION_SERVICE)
7/37
1. 통지
 통지 출력
 통지 기능을 이용한 예제를 통해 실습해 보자.
service/NapAlarm
public class NapAlarm extends Activity {
static final int NAPNOTI = 1;
NotificationManager mNotiManager;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.napalarm);
mNotiManager =
(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Button btn = (Button)findViewById(R.id.start);
btn.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
Toast.makeText(NapAlarm.this, "안녕히 주무세요", 0).show();
v.postDelayed(new Runnable() {
public void run() {
Notification noti = new Notification(R.drawable.napalarm,
"일어나세요",System.currentTimeMillis());
noti.defaults |= Notification.DEFAULT_SOUND;
noti.flags |= Notification.FLAG_INSISTENT;
Intent intent = new Intent(NapAlarm.this,
NapEnd.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_
TASK);
PendingIntent content = PendingIntent.getActivity(
NapAlarm.this, 0, intent, 0);
noti.setLatestEventInfo(NapAlarm.this, "기상 시
간",
"일어나! 일할 시간이야.", content);
mNotiManager.notify(NapAlarm.NAPNOTI, noti);
}
}, 5 * 1000);
}
});
}
}
8/37
1. 통지
 통지 출력
 통지 기능을 이용한 예제를 통해 실습해 보자.
service/NapEnd
public class NapEnd extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.napend);
NotificationManager NM = (NotificationManager)
getSystemService(NOTIFICATION_SERVICE);
NM.cancel(NapAlarm.NAPNOTI);
Button btn = (Button)findViewById(R.id.end);
btn.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
finish();
}
});
}
}
9/37
1. 통지
 커스텀 통지 뷰
 확장된 상태란에 출력되는 문자열들은 setLatesEventInfo 메서드로 간편하게 지정할 수
있다.
service/customnotiview.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/napview"
/>
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="일어나!"
android:textColor="#000000"
android:textSize="9pt"
android:layout_gravity="center_vertical"
/>
</LinearLayout>
10/37
1. 통지
 커스텀 통지 뷰
 통상적인 뷰로 생성해서 안되면 프로세스의 경계를 넘어 출력할 수 있는 Remote View
클래스의 객체를 생성해야 한다.
 생성자로 패키지 이름과 레이아웃 리소스의 id를 전달한다.
• RemoteViews(String packageName, int layoutId)
 이미지와 텍스트 내용이 고정적이라면 XML 파일에 미리 대입해 놓는 것이 편하며, 통
지의 내용에 따라 가변적이라면 다음 메서드로 이미지와 텍스트를 실시간으로 결정해서
대입한다.
• setImageViewResource(int viewId, int srcId)
• setTextViewText(int viewId, CharSequence text)
11/37
2. BR
 방송
 방송을 청취하려는 응용 프로그램은 BR(Broadcast Receiver : 방송 수신자)를 작성해 두
고 관심 있는 방송을 수신한다.
 BR은 안드로이드 응용 프로그램을 구성하는 4개의 컴포넌트 중 하나로서 오로지 방송
수신 대기만 하며 사용자와 직접 대면은 하지 않는다.
 BroadcastReceiver 클래스로부터 상속받으며 방송을 수신하는 다음 메서드를 재정의 한
다.
• void onReceive (Context context, Intent intent)
 방송이 수신되면 onReceive 메서드가 호출되며, context는 BR이 실행되는 컨텍스트이며
intent는 수신된 방송 내용이다.
 BR은 프로세스의 메인 스레드에서 실행된다.
 10초 내로 onReceive 메서드가 리턴하지 않으면 시스템은 응답이 없는 것으로 판별하여
강제로 죽인다.
12/37
2. BR
 방송
 방송은 응용 프로그램끼리 통신하는 공식적인 수단을 활용하는데 응용 프로그램이 방송
을 할 때는 다음 메서드로 호출한다.
• void sendBroadcast (Intent intent [, String receiverPermission])
• void sendOrderedBroadcast (Intent intent, String receiverPermission)
 Intent 인수는 전달하고자 하는 방송 내용이며 액션에 방송의 주 내용을 대입하며 인텐
트의 다른 필드에 추가 정보도 전달할 수 있다.
 일반 방송은 비동기적으로 동작하여 호출 시 즉시 리턴한다.
 순서 있는 방송은 인텐트 필터의 android:priority 속성이 지정하는 중요도에 따라 수신
순서가 결정되어 차례대로 전달된다.
13/37
2. BR
 방송 (실습 예제)
service/DetectFree
public class DetectFree extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.detectfree);
Button btn = (Button)findViewById(R.id.brfree);
btn.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("exam.service.FREEWIFI");
sendBroadcast(intent);
}
});
}
}
Network/FreeBR
public class FreeBR extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Intent intent2 = new Intent(context, DownHtml.class);
intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent2);
}
}
14/37
2. BR
 방송
 액티비티가 실행중인 동안만 방송을 수신하려면 코드에서 BR을 일시적으로 등록 해 놓
을 수 있으며, 필요할 때만 방송을 수신하려면 매니페스트에 등록할 필요없이 다음 메서
드로 등록 및 해제 한다.
• Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter)
• void unregisterReceiver (BroadcastReceiver receiver)
 등록 메서드로 BR 객체와 인텐트 필터를 전달한다.
 BR을 등록하는 최적의 시점은 onResume이며 등록을 해제할 최적의 시점은 onPause이
다.
15/37
2. BR
 방송 (실습 예제2)
service/DetectSaveZone
service/OnSaveZone
public class DetectSaveZone extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.detectsavezone);
public class OnSaveZone extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.onsavezone);
}
Button btn = (Button)findViewById(R.id.brsavezone);
btn.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
v.postDelayed(new Runnable() {
public void run() {
Intent intent = new Intent();
intent.setAction("exam.service.SAVEZONE");
sendBroadcast(intent);
}
}, 10000);
}
});
public void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction("exam.service.SAVEZONE");
registerReceiver(mSaveZoneBR, filter);
}
public void onPause() {
super.onPause();
unregisterReceiver(mSaveZoneBR);
}
}
}
BroadcastReceiver mSaveZoneBR = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "아싸! 공짜다.",
Toast.LENGTH_LONG).show();
}
};
}
16/37
2. BR
 방송 (실습 예제2)
17/37
2. BR
 배터리 감시
 모바일 장비는 항상 배터리로 동작하며 배터리가 없으면 아무것도 할 수 없으며 배터리
의 남은 양은 모든 응용 프로그램이 관을 가져야 할 중요한 정보이다.
 배터리와 관련된 방송들은 다음과 같이 여러 가지가 있다.
액션
설명
ACTION_BATTERY_CHANGED
배터리의 충전 상태가 변경되었다. 이 방송은 매니페스트에 등록
해서는 받을 수 없으며 registerReceiver 메서드로 명시적으로
등록해야 받을 수 있다.
ACTION_BATTERY_LOW
배터리 상태가 위험 수준으로 낮아졌다.
ACTION_BATTERY_OKAY
배터리 상태가 위험 수준에서 양호한 상태로 전환되었다. 위험
수준을 벗어 날 때 딱 한번만 방송된다.
ACTION_POWER_CONNECTED
외부 전원이 연결되었다. 응용 프로그램이 활성화 상태가 아니어
도 이 방송을 받을 수 있다.
ACTION_POWER_DISCONNECTED
외부 전원이 분리되었다. 응용 프로그램이 활성화 상태가 아니어
도 이 방송을 받을 수 있다.
 대개의 경우 ACTION_BATTERY_CHANGED 방송만 청취해도 변화는 다 알아낼 수 있
다.
18/37
2. BR
 배터리 감시
 배터리 상태에 대한 상세한 정보는 인텐트의 Extras에 실려 방송 수신자에게 전달된다
 조사 가능한 값들은 BatteryManager 클래스에 상수로 정의되어 있다.
상태
설명
EXTRA_PRESENT
배터리가 존재하는지를 조사한다.
EXTRA_PLUGGED
외부 전원에 연결되어 있는지를 조사한다. 0이면 배터리가 있다는 뜻이고 그 외의 경우는 다른 전원에
연결되어 있다는 뜻이다. BATTERY_PLUGGED_AC는 어댑터 연결을 의미하며
BATTERY_PLUGGED_USB는 USB 케이블 연결을 의미한다
EXTRA_STATUS
배터리의 현재 상태를 나타내며 다음과 같은 상수들이 정의되어 있다.
BATTERY_STATUS_CHARGING : 충전중이다.
BATTERY_STATUS_DISCHARGING : 방전중이다.
BATTERY_STATUS_FULL : 가득 충전되었다.
BATTERY_STATUS_NOT_CHARGING : 충전중이 아니다.
BATTERY_STATUS_UNKNOWN : 상태를 알 수 없다.
EXTRA_SCALE
배터리 레벨의 최대량을 조사한다.
EXTRA_LEVEL
현재 충전 레벨을 조사한다.
EXTRA_HEALTH
배터리의 성능 상태를 조사한다.
EXTRA_ICON_SMALL
배터리 상태를 표시하는 아이콘의 리소스 ID를 조사한다.
EXTRA_TECHNOLOGY
배터리의 방식을 조사한다.
EXTRA_TEMPERATURE
온도를 조사한다.
EXTRA_VOLTAGE
전압을 조사한다.
19/37
2. BR
 배터리 감시 (실습 예제)
service/WatchBattery
public class WatchBattery extends Activity {
TextView mStatus;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.watchbattery);
mStatus = (TextView)findViewById(R.id.status);
}
public void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(Intent.ACTION_BATTERY_LOW);
filter.addAction(Intent.ACTION_BATTERY_OKAY);
filter.addAction(Intent.ACTION_POWER_CONNECTED);
filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
registerReceiver(mBRBattery, filter);
}
public void onPause() {
super.onPause();
unregisterReceiver(mBRBattery);
}
BroadcastReceiver mBRBattery = new BroadcastReceiver() {
int Count = 0;
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Count++;
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
onBatteryChanged(intent);
}
if (action.equals(Intent.ACTION_BATTERY_LOW)) {
Toast.makeText(context, "배터리 위험 수준",
Toast.LENGTH_LONG).show();
}
if (action.equals(Intent.ACTION_BATTERY_OKAY)) {
Toast.makeText(context, "배터리 양호",
Toast.LENGTH_LONG).show();
}
if (action.equals(Intent.ACTION_POWER_CONNECTED)) {
Toast.makeText(context, "전원 연결됨",
Toast.LENGTH_LONG).show();
}
if
(action.equals(Intent.ACTION_POWER_DISCONNECTED))
{
Toast.makeText(context, "전원 분리됨",
Toast.LENGTH_LONG).show();
}
}
20/37
2. BR
 배터리 감시 (실습 예제)
public void onBatteryChanged(Intent intent) {
int plug, status, scale, level, ratio;
String sPlug = " ";
String sStatus = " ";
if (intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, false)
==
false){
mStatus.setText("배터리 없음");
return;
}
plug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100);
level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
ratio = level * 100 / scale;
switch (plug) {
case BatteryManager.BATTERY_PLUGGED_AC:
sPlug = "AC";
break;
case BatteryManager.BATTERY_PLUGGED_USB:
sPlug = "USB";
break;
default:
sPlug = "Battery";
break;
}
switch (status) {
case BatteryManager.BATTERY_STATUS_CHARGING:
sStatus = "충전중";
break;
case
BatteryManager.BATTERY_STATUS_NOT_CHARGING:
sStatus = "충전중 아님";
break;
case BatteryManager.BATTERY_STATUS_DISCHARGING:
sStatus = "방전중";
break;
case BatteryManager.BATTERY_STATUS_FULL:
sStatus = "만충전";
break;
default:
case BatteryManager.BATTERY_STATUS_UNKNOWN:
sStatus = "알 수가 없어";
break;
}
21/37
2. BR
 배터리 감시 (실습 예제)
String str = String.format("수신 회수:%d\n연결: %s\n상태:%s\n
레벨:%d%%",
Count, sPlug, sStatus, ratio);
mStatus.setText(str);
}
};
}
22/37
2. BR
 배터리 감시
 에뮬레이터는 배터리를 쓰지 않기 때문에 충전의 개념이 없으며 테스트해 보기 쉽지 않
으며 항상 충전 중으로 표시되며 충전 레벨은 50%로 고정되어 있다.
 에뮬레이터에서 테스트 해보려면 텔넷으로 에뮬레이터에 접속한 후 배터리의 상태를 인
위적으로 변경하는 명령을 다음 실행과 같다.
• telnet localhost 5554
 5554는 에뮬레이터와 연결되는 포트 번호이며 에뮬레이트넌 통상 5554번이다.
 텔넷이 없는 시스템에서는 Zterm이나 putty같은 공개 텔넷 프로그램을 사용할 수 있다.
23/37
2. BR
 배터리 감시
 Putty로 에뮬레이터에 접속하는 모습은 다음과 같다.
24/37
2. BR
 배터리 감시
 텔넷에 접속한 후 다음 명령으로 에뮬레이터의 배터리 상태를 변경해 볼 수 있다.
명령
설명
power capacity n
배터리 레벨을 변경한다. n은 0~100까지이다.
power ac on/off
외부 전원을 연결 또는 해제한다.
power status 상태
배터리의 상태를 변경한다. 지정 가능한 상태는 charging, discharging,
not-charging, full, unknown 등이 있다.
power health
배터리의 성능을 조사한다.
power present true/false
배터리를 탈부착한다.
power display
배터리의 현재 상태를 조사한다.
25/37
2. BR
 SD 카드 감시
 안드로이드는 SD카드를 외부 저장 장치로 사용하며 데이터 파일은 모두 SD 카드에 저
장해야 한다.
 SD카드는 장비의 전원이 들어와 있는 상태에서 언제든지 삽입, 분리, 교체가 가능하다.
 SD 카드와 관련된 방송 액션은 다음과 같다.
액션
설명
ACTION_MEDIA_MOUNTED
외부 미디어가 존재하며 제 위치에 마운트되었다. 마운트된 경로는 인
텐트의 mData 필드로 조사할 수 있으며 read-only 값은 읽기 전용 미
디어인지를 조사한다.
ACTION_MEDIA_UNMOUNTED
외부 미디어가 존재하지만 제 위치에 마운트되지 않았다.
ACTION_MEDIA_EJECT
사용자가 외부 미디어의 제거를 명령했다. 응용 프로그램은 열려진 모
ACTION_MEDIA_REMOVED
외부 미디어가 제거되었다.
ACTION_MEDIA_NOFS
외부 미디어가 존재하지만 인식하지 못하는 파일 시스템이거나 빈 미
디어이다.
ACTION_MEDIA_SCANNER_STARTED
미디어 스캐너가 스캔을 시작했다.
ACTION_MEDIA_SCANNER_FINISHED
미디어 스캔을 종료했다.
ACTION_MEDIA_SCANNER_SCAN_FILE
파일을 검색했으며 DB에 파일을 추가한다.
든 파일을 닫아야 한다.
26/37
2. BR
 SD 카드 감시 (실습 예제)
service/WatchSDCard
public class WatchSdcard extends Activity {
TextView mStatus;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.watchsdcard);
mStatus = (TextView)findViewById(R.id.status);
}
public void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
filter.addAction(Intent.ACTION_MEDIA_REMOVED);
filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
filter.addAction(Intent.ACTION_MEDIA_EJECT);
filter.addAction(Intent.ACTION_MEDIA_NOFS);
filter.addDataScheme("file");
registerReceiver(mBRSdcard, filter);
BroadcastReceiver mBRSdcard = new BroadcastReceiver() {
int Count = 0;
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Count++;
String str = String.format("수신 회수:%d, 위치:%s", Count,
intent.getData().toString());
mStatus.setText(str);
if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
boolean readonly = intent.getBooleanExtra("read-only", false);
String mount = "미디어 장착: " + (readonly ? "읽기 전용":"읽기 쓰
기 가능");
Toast.makeText(context, mount, Toast.LENGTH_SHORT).show();
}
if (action.equals(Intent.ACTION_MEDIA_REMOVED)) {
Toast.makeText(context, "미디어 분리",
Toast.LENGTH_SHORT).show();
}
if (action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) {
Toast.makeText(context, "미디어 잘못된 위치에 장착",
Toast.LENGTH_SHORT).show();
}
}
public void onPause() {
super.onPause();
unregisterReceiver(mBRSdcard);
}
27/37
2. BR
 SD 카드 감시 (실습 예제)
if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
Toast.makeText(context, "미디어 제거 요청",
Toast.LENGTH_SHORT).show();
}
if (action.equals(Intent.ACTION_MEDIA_NOFS)) {
Toast.makeText(context, "미디어 인식 안됨",
Toast.LENGTH_SHORT).show();
}
}
};
}
28/37
2. BR
 알람
 알람은 미리 지정해 놓은 시간에 이벤트를 방생시키는 시스템 장치이다.
 알람은 운영체제가 관리하며 응용 프로그램 외부에서도 설정 가능하다.
 알람은 AlarmManager 클래스로 관리하며, 시스템 서비스이며 공개된 생성자가 없으므
로 직접 생성할 수 없으며 컨텍스트의 다음 메서드로 인스턴스를 구한다.
• Context.getSystemService(Context.ALARM_SERVICE);
 알람 매니저의 다음 메서드로 알람을 등록하며 한번만 동작하는 알람과 주기적으로 반
복하는 알람 두 가지 종류가 있다.
• void set (int type, long triggerAtTime, PendingIntent operation)
• void setRepeating (int type, long triggerAtTime, long interval, PendingIntent operation)
 set 메서드는 딱 한번만 동작하는 알람을 등록하며 setRepeating은 주기를 정해 놓고 반
복적으로 동작하는 알람을 등록한다.
29/37
2. BR
 알람
 인수 type은 예약 시간을 해석하는 방법과 예약 시간에 장비가 슬립 모드일 때 장비의
기동 여부를 지정하는데 다음 4가지 값 중 하나를 사용할 수 있다.
값
설명
RTC
System.currentTimeMillis() 메서드로 구한 세계 표준시(UTC)로 지
정한다.
RTC_WAKEUP
위와 같되 장비를 깨운다.
ELAPSED_REALTIME
SystemClock.elapsedRealtime() 메서드로 구한 부팅된 이후의 경과
시간으로 지정한다.
ELAPSED_REALTIME_WAKEUP
위와 같되 장비를 깨운다.
 triggerAtTime 인수는 알람을 기동할 시간을 지정하는데 포맷은 type에 따라 달라진다.
30/37
2. BR
 알람 (실습 예제)
service/AlarmTest.java
public class AlarmTest extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.alarmtest);
Button btn;
btn = (Button)findViewById(R.id.onetime);
btn.setOnClickListener(mClick);
btn = (Button)findViewById(R.id.repeat);
btn.setOnClickListener(mClick);
btn = (Button)findViewById(R.id.stop);
btn.setOnClickListener(mClick);
}
Button.OnClickListener mClick = new Button.OnClickListener() {
public void onClick(View v) {
AlarmManager am =
(AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent;
PendingIntent sender;
switch (v.getId()) {
case R.id.onetime:
// 예약에 의해 호출될 BR 지정
intent = new Intent(AlarmTest.this, AlarmReceiver.class);
sender = PendingIntent.getBroadcast(AlarmTest.this,0,intent,0);
// 알람 시간. 10초 후
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 10);
// 알람 등록
am.set(AlarmManager.RTC, calendar.getTimeInMillis(), sender);
break;
case R.id.repeat:
case R.id.stop:
intent = new Intent(AlarmTest.this, DisplayScore.class);
sender = PendingIntent.getBroadcast(AlarmTest.this,0,intent,0);
// 8초당 한번 알람 등록
if (v.getId() == R.id.repeat) {
am.setRepeating(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime(),
6000, sender);
} else {
am.cancel(sender);
}
break;
}
}
};
}
31/37
2. BR
 알람 (실습 예제)
service/AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "It’s time to start",
Toast.LENGTH_LONG).show();
}
}
32/37
3. 서비스
 데몬
 서비스는 백그라운드에서 실행되며 사용자와 직접적인 상호작용은 하지 않는다.
 클라이언트에서 어떤 식으로 호출하는가에 따라 다음 두 가지 사용 방법이 있다.
• 백그라운드 데몬 : 배경에서 계속 실행되는 프로세스이다.
• 원격 호출 인터페이스 : 클라이언트를 위한 특정한 기능을 제공하는 역할은 한다.
 서비스의 생명주기는 액티비티에 비해서 아주 단순하다.
33/37
3. 서비스
 데몬 (실습 예제)
service/NewsServce.java
public class NewsService extends Service {
boolean mQuit;
public void onCreate() {
super.onCreate();
}
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service End", 0).show();
mQuit = true;
}
public int onStartCommand (Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
mQuit = false;
NewsThread thread = new NewsThread(this, mHandler);
thread.start();
return START_STICKY;
}
public IBinder onBind(Intent intent) {
return null;
}
class NewsThread extends Thread {
NewsService mParent;
Handler mHandler;
String[] arNews = {
"일본, 독도는 한국땅으로 인정",
"번데기 맛 쵸코파이 출시",
"춘천 지역에 초거대 유전 발견",
"한국 월드컵 결승 진출",
"국민 소득 6만불 돌파",
"학교 폭력 완전 근절된 것으로 조사",
"안드로이드 점유율 아이폰을 앞질렀다",
};
public NewsThread(NewsService parent, Handler handler) {
mParent = parent;
mHandler = handler;
}
public void run() {
for (int idx = 0;mQuit == false;idx++) {
Message msg = new Message();
msg.what = 0;
msg.obj = arNews[idx % arNews.length];
mHandler.sendMessage(msg);
try { Thread.sleep(5000);} catch (Exception e) { ; }
}
}
}
Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == 0) {
String news = (String)msg.obj;
Toast.makeText(NewsService.this, news, 0).show();
}
}
};
}
34/37
3. 서비스
 데몬 (실습 예제)
service/NewsController.java
public class NewsController extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.newscontroller);
Button btnstart = (Button)findViewById(R.id.newsstart);
btnstart.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(NewsController.this,NewsService.class);
startService(intent);
}
});
Button btnend = (Button)findViewById(R.id.newsend);
btnend.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(NewsController.this,NewsService.class);
stopService(intent);
}
});
}
}
35/37
3. 서비스
 원격 인터페이스
 안드로이드는 원격 인터페이스를 정의하는 AIDL 이라는 별도의 언어를 제공하며 AIDL
컴파일러가 인터페이스 정의를 구현하는 스텁까지 생성해 준다.
 AIDL소스를 작성하여 프로젝트에 포함시켜 놓으면 AIDL컴파일러가 인터페이스를 구
현하는 자바 파일을 생성하여 gen 폴더에 배치한다.
 다음 소스는 Icalc 인터페이스에 최소 공배수를 조사하는 메서드와 소수 여부를 조사하
는 메서드의 원현을 선언하는 예이다.
service/Icalc.aidl
package exam.service;
interface ICalc {
int getLCM(in int a, in int b);
boolean isPrime(in int n);
}
36/37
3. 서비스
 원격 인터페이스 (실습 예제)
mResult.setText("7의 소수 여부 = " + prime);
service/CalcClient
public class CalcClient extends Activity {
ICalc mCalc;
TextView mResult;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.calcclient);
mResult = (TextView)findViewById(R.id.result);
Button btnLCM = (Button)findViewById(R.id.btnLCM);
btnLCM.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
int LCM = 0;
try {
LCM = mCalc.getLCM(6, 8);
} catch (RemoteException e) {
e.printStackTrace();
}
mResult.setText("6과 8의 최소 공배수 = " + LCM);
}
});
Button btnPrime = (Button)findViewById(R.id.btnPrime);
btnPrime.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
boolean prime = false;
try {
prime = mCalc.isPrime(7);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
public void onResume() {
super.onResume();
Intent intent = new Intent(this, CalcService.class);
bindService(intent, srvConn, BIND_AUTO_CREATE);
}
public void onPause() {
super.onPause();
unbindService(srvConn);
}
ServiceConnection srvConn = new ServiceConnection() {
public void onServiceConnected(ComponentName
className, IBinder binder) {
mCalc = ICalc.Stub.asInterface(binder);
}
public void onServiceDisconnected(ComponentName className) {
mCalc = null;
}
};
}
37/37
안드로이드 프로그래밍 정복(Android Programming Complete
Guide)

similar documents