특정 시간에 Notification 발생 시키기
특정 시간이 되면 알림이 발생되는 코드를 android에서 구현해보도록 하겠습니다. 특정 시간을 설정해서 그 시간이 되면 알려주는 무엇인가가 있어야하는데 이를 가능하게 만들어주는 것이 AlarmManager입니다. 코드를 통해서 알아보도록 합시다.
먼저 레이아웃은 간단하게 아래처럼 구성되어있습니다.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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"
android:orientation="vertical"
tools:context=".MainActivity">
<TimePicker
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:timePickerMode="spinner"
android:id="@+id/time_picker" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="저장"
android:id="@+id/save"/>
</LinearLayout>
이제 time_picker에서 시간을 설정하고 save 버튼을 누르게 되면 그 시간에 Notification이 발생하게 되는 코드를 설명합니다.
MainActivity
MainActivity의 onCreate 코드는 아래와 같습니다.
package com.reak.alarmtest;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.TimePicker;
import android.widget.Toast;
import java.util.Calendar;
public class MainActivity extends AppCompatActivity {
private Button save;
private TimePicker timePicker;
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
timePicker=(TimePicker)findViewById(R.id.time_picker);
save=(Button)findViewById(R.id.save);
save.setOnClickListener(v->{
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
int hour=timePicker.getHour();
int minute=timePicker.getMinute();
calendar.set(Calendar.HOUR_OF_DAY,hour);
calendar.set(Calendar.MINUTE,minute);
if (calendar.before(Calendar.getInstance())) {
calendar.add(Calendar.DATE, 1);
}
AlarmManager alarmManager=(AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
if (alarmManager != null) {
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, alarmIntent);
Toast.makeText(MainActivity.this,"알람이 저장되었습니다.",Toast.LENGTH_LONG).show();
}
});
}
}
여기서 Calendar 객체를 현재시간으로 미리 설정해두고, set 메소드로 timePicker에서 설정된 시간과 분으로 설정시키는 것입니다. 이때 시간과 분을 TimePicker에서 얻어오려면 @RequiresApi(api = Build.VERSION_CODES.M) 를 메소드위에 추가시켜야합니다.
이제 AlarmManager를 가져옵니다. Intent는 수신자 클래스를 전달하게 됩니다. 여기서는 AlarmReceiver라는 수신자이며 밑에서 이 Receiver를 구현하게 될겁니다. 그리고 PendingIntent를 얻어와서 setRepeating 메소드로 정확한 시간에 알람을 설정시켜줍니다.
여기서 setRepeating메소드는 알람을 반복시키는 메소드입니다. 여기서는 AlarmManager.INTERVAL_DAY를 사용하였고, 이것은 매일 알람이 울릴것을 명시해준것입니다.
굳이 정확한 시간에 알람을 울리지 않을 경우에는 setInexactRepeating 메소드를 사용할 수도 있습니다. 실제로 안드로이드 개발문서에는 이 메소드를 사용하라고 권고하고 있네요.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.reak.alarmtest">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AlarmTest">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".AlarmReceiver"/>
</application>
</manifest>
수신자를 사용하려면 위에서처럼 메니페스트에 수신자를 명시해주어야합니다.
AlarmReceiver
package com.reak.alarmtest;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.media.RingtoneManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import androidx.core.app.NotificationCompat;
import java.util.Calendar;
import java.util.StringTokenizer;
import static android.app.Notification.EXTRA_NOTIFICATION_ID;
public class AlarmReceiver extends BroadcastReceiver {
private Context context;
private String channelId="alarm_channel";
@Override
public void onReceive(Context context, Intent intent) {
this.context = context;
Intent busRouteIntent = new Intent(context, MainActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addNextIntentWithParentStack(busRouteIntent);
PendingIntent busRoutePendingIntent =
stackBuilder.getPendingIntent(1, PendingIntent.FLAG_UPDATE_CURRENT);
final NotificationCompat.Builder notificationBuilder=new NotificationCompat.Builder(context,channelId)
.setSmallIcon(R.mipmap.ic_launcher).setDefaults(Notification.DEFAULT_ALL)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setAutoCancel(true)
.setContentTitle("알람")
.setContentText("울림")
.setContentIntent(busRoutePendingIntent);
final NotificationManager notificationManager=(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
NotificationChannel channel=new NotificationChannel(channelId,"Channel human readable title",NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
int id=(int)System.currentTimeMillis();
notificationManager.notify(id,notificationBuilder.build());
}
}
이제 알람이 발생되면 AlarmReceiver의 onReceive 메소드가 호출되게 됩니다. 이때 아까 우리가 MainActivity에서 넘긴 PendingIntent를 requestCode를 통해서 얻어올 수가 있습니다. 이 requestCode는 알람을 설정했던 것과 같은 코드를 사용해야합니다. 여기서는 1입니다.
오레오(Oreo)버전 이상부터는 NotificationChannel을 명시해주어야합니다. 그 코드도 적용되어 있습니다.
대충 완성하게 되면 아래와 같은 모습입니다. 앱 디자인은 개나 줘버린 모습이지만 구현이 제대로 되었나 확인만 하는 용도입니다.
그리고 원하는 시간에 알람을 저장시켜줍니다. 그래서 9시 15분에 알람을 설정합니다. 그리고 그 시간에 울리는 지 잠깐 기다려주겠습니다. 이때 9시 14분이었고, 1분만 기다리면 됩니다.
다음은 알람이 발생되어 Notification이 발생된 화면입니다.
분명 9시 15분이었는데, 9시 16분에 알람이 발생되었군요. 정확한 시간에 알람이 딱 울리지는 않는 것 같습니다. 제 생각에는 setRepeating이 setInexactRepeating메소드보다 더 정확한 시간에 발생시켜주는 것으로 확인이 됩니다.
알람 취소
그리고 알람을 취소하려면 아래와 같이 코드를 추가하면 되는데요. 위의 코드는 없지만 만약 알람 취소버튼을 추가하고 그 버튼이 눌리면 alarmManager의 cancel 메소드를 이용하면 됩니다.
PendingIntent cancelIntent=PendingIntent.getBroadcast(MainActivity.this, 1, intent,PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.cancel(cancelIntent);
여기까지 Alarm과 Notification, Receiver를 조합하여 앱을 구현해보았습니다.
'안드로이드' 카테고리의 다른 글
[안드로이드] Google Native 광고 구현 시 Module Import 안될때 해결방법 (0) | 2021.11.07 |
---|---|
[Android] 간단 코딩 - SwipeRefreshLayout을 이용하여 새로 고침하기 (0) | 2021.08.24 |
[안드로이드] XmlPullParser로 Xml 파싱하는 방법 - 코드 예제 (0) | 2021.05.26 |
[안드로이드] 서울시 버스 도착 정보 조회 api 사용 - 공공데이터포털 Open API (0) | 2021.05.01 |
[안드로이드] RecyclerView 수평 이동 및 한번에 항목 하나만 보이게 만들기 (0) | 2020.07.01 |