Transcript ch16 서비스
서비스
안드로이드 프로그래밍 정복(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)