개발자 승학

안드로이드 스튜디오 알람 앱 예제(Alarm) 본문

it/안드로이드(android studio)

안드로이드 스튜디오 알람 앱 예제(Alarm)

유승학 2018. 9. 13. 12:37

안녕하세요.


이번에는 간단한 알람 앱을 만들어 볼려고 합니다.


우선 이 예제에서는 4대 컴포넌트 하나인 BroadcastReceiver와 Service를 사용합니다.


우선, BroadcasReceiver는 단말기 안에서 행해지는 수 많은 일들을 대신해서 알려주는 방송? 이라고 생각하면 쉬울 듯 합니다.


BroadcastReceiver는 매니패스트에 등록해야 사용이 가능합니다.


다음으로 알람음을 재생시키는 Service입니다.


Service또한 4대 컴포넌트 중 하나입니다.


Activty와 다리 백그라운드에서 동작하는 컴포넌트 입니다.


사용자가 알람시간을 설정하고 핸드폰을 화면을 끈 상태로 알람을 맞춰두고 무슨 일을 하겠죠?


그래서 백그라운드에서 실행하기위해 Service가 필요합ㄴ디ㅏ.


메모리 부족같은 특별한 경우를 제외하고는 수행합니다.


Service또한 매니페스트에 등록해야합니다.




먼저 아무 mp3파일을 준비합니다.


res -> raw에 넣어줍니다.



다음으로 디자인부터 만들어 볼게요~


[activity_main.xml]

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical"
android:gravity="top">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="편히 주무세요! 깨워 드릴게요"
android:textSize="30sp"
android:layout_marginBottom="10dp"/>

<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TimePicker
android:id="@+id/time_picker"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<Button
android:layout_width="60dp"
android:layout_height="50dp"
android:id="@+id/btn_start"
android:text="시작"/>

<Button
android:layout_width="60dp"
android:layout_height="50dp"
android:id="@+id/btn_finish"
android:text="종료" />

</LinearLayout>

</LinearLayout>


시작과 종류 두 개의 버튼과 알람시간을 선택하는 타임피커를 하나 만듭니다.


시작 버튼을 타임피컬르 통해 지정한 시간에 알람을 울리게 하는 버튼이고


종료 버튼은 해당 시간이 되면 알람음이 울려서 알람음을 중지하는 버튼입니다.



[MainActivity.java]


public class MainActivity extends AppCompatActivity{

AlarmManager alarm_manager;
TimePicker alarm_timepicker;
Context context;
PendingIntent pendingIntent;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

this.context = this;

// 알람매니저 설정
alarm_manager = (AlarmManager) getSystemService(ALARM_SERVICE);

// 타임피커 설정
alarm_timepicker = findViewById(R.id.time_picker);

// Calendar 객체 생성
final Calendar calendar = Calendar.getInstance();

// 알람리시버 intent 생성
final Intent my_intent = new Intent(this.context, Alarm_Reciver.class);

// 알람 시작 버튼
Button alarm_on = findViewById(R.id.btn_start);
alarm_on.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onClick(View v) {

// calendar에 시간 셋팅
calendar.set(Calendar.HOUR_OF_DAY, alarm_timepicker.getHour());
calendar.set(Calendar.MINUTE, alarm_timepicker.getMinute());

// 시간 가져옴
int hour = alarm_timepicker.getHour();
int minute = alarm_timepicker.getMinute();
Toast.makeText(MainActivity.this,"Alarm 예정 " + hour + "시 " + minute + "분",Toast.LENGTH_SHORT).show();

// reveiver에 string 값 넘겨주기
my_intent.putExtra("state","alarm on");

pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, my_intent,
PendingIntent.FLAG_UPDATE_CURRENT);

// 알람셋팅
alarm_manager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
pendingIntent);
}
});

// 알람 정지 버튼
Button alarm_off = findViewById(R.id.btn_finish);
alarm_off.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"Alarm 종료",Toast.LENGTH_SHORT).show();
// 알람매니저 취소
alarm_manager.cancel(pendingIntent);

my_intent.putExtra("state","alarm off");

// 알람취소
sendBroadcast(my_intent);
}
});
}
}


[Alarm_Receiver.java]

public class Alarm_Reciver extends BroadcastReceiver{

Context context;

@Override
public void onReceive(Context context, Intent intent) {

this.context = context;
// intent로부터 전달받은 string
String get_yout_string = intent.getExtras().getString("state");

// RingtonePlayingService 서비스 intent 생성
Intent service_intent = new Intent(context, RingtonePlayingService.class);

// RingtonePlayinService로 extra string값 보내기
service_intent.putExtra("state", get_yout_string);
// start the ringtone service

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O){
this.context.startForegroundService(service_intent);
}else{
this.context.startService(service_intent);
}
}
}

<receiver android:name=".Alarm_Reciver" />

매니패스트에 해당 클래스를 등록합니다.



마지막으로 BroadcastReceiver로부터 string 값을 받아 음악을 재생시킬지 말지를 수행하는 Service입니다.



[RingtonePlayingService.java]


public class RingtonePlayingService extends Service{

MediaPlayer mediaPlayer;
int startId;
boolean isRunning;

@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}

@Override
public void onCreate() {
super.onCreate();

if (Build.VERSION.SDK_INT >= 26) {
String CHANNEL_ID = "default";
NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT);

((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);

Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("알람시작")
.setContentText("알람음이 재생됩니다.")
.setSmallIcon(R.mipmap.ic_launcher)

.build();

startForeground(1, notification);
}
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

String getState = intent.getExtras().getString("state");

assert getState != null;
switch (getState) {
case "alarm on":
startId = 1;
break;
case "alarm off":
startId = 0;
break;
default:
startId = 0;
break;
}

// 알람음 재생 X , 알람음 시작 클릭
if(!this.isRunning && startId == 1) {

mediaPlayer = MediaPlayer.create(this,R.raw.ouu);
mediaPlayer.start();

this.isRunning = true;
this.startId = 0;
}

// 알람음 재생 O , 알람음 종료 버튼 클릭
else if(this.isRunning && startId == 0) {

mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.release();

this.isRunning = false;
this.startId = 0;
}

// 알람음 재생 X , 알람음 종료 버튼 클릭
else if(!this.isRunning && startId == 0) {

this.isRunning = false;
this.startId = 0;

}

// 알람음 재생 O , 알람음 시작 버튼 클릭
else if(this.isRunning && startId == 1){

this.isRunning = true;
this.startId = 1;
}

else {
}
return START_NOT_STICKY;
}

@Override
public void onDestroy() {
super.onDestroy();

Log.d("onDestory() 실행", "서비스 파괴");

}
}


   <service
android:name=".RingtonePlayingService"
android:enabled="true"></service>
</application>

매니페스트 등록



Service를 사용할 때 주의할점은 메인 쓰레드 안에서 실행됩니다. 많은 쓰레드 작업이 필요할 경우 결도로 쓰레드를 생성하여 작업을 행해야 합니다. 


서비스의 생명주기입니다.


BroadcastReceiver로부터 startService()를 호출해서 서비스가 시작되었다면 stop서비스가 호출 될 때까지 서비스가 계속 실행됩니다.


[깃허브]

https://github.com/aiex1234/PleaseWakeMeUp


궁금하신점은 댓글을 달아주세요










Comments