이 튜토리얼에서는 안드로이드 앱에서 사용자가 지정한 날짜(만료 날짜)에 자동으로 표시되는 예약 알림을 만드는 방법을 단계별로 알아봅니다. 핵심 원리는 다음과 같습니다.
- DatePickerDialog – 사용자에게 날짜를 입력받습니다.
- AlarmManager – 지정된 시점에 브로드캐스트를 예약합니다.
- BroadcastReceiver – 알람이 울리는 순간 실제 알림을 게시합니다.
1단계: 새 프로젝트 생성
Android Studio에서 File → New Project를 선택하고 새 프로젝트를 생성한 뒤, 필요한 정보를 모두 입력합니다. 언어는 Java, 최소 SDK는 알림 채널이 필요한 API 26(Android 8.0) 이상으로 설정하는 것을 권장합니다.
2단계: 레이아웃 작성 (res/layout/activity_main.xml)
화면에는 날짜를 선택할 수 있는 TextView 하나만 배치합니다. 탭하면 날짜 선택 다이얼로그가 열리도록 android:onClick 속성을 지정합니다.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/btnDate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Select Date"
android:onClick="setDate"
android:padding="16dp" />
</RelativeLayout>
※ 주의: 자바 코드에서 R.id.btnDate를 참조하므로, 뷰의 ID도 반드시 btnDate로 일치시켜야 합니다.
3단계: MainActivity 구현 (src/MainActivity.java)
메인 액티비티에서는 날짜 선택, 알림 객체 생성, 알람 예약의 세 가지 역할을 수행합니다.
package app.tutorialspoint.com.notifyme;
import android.app.AlarmManager;
import android.app.DatePickerDialog;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
public class MainActivity extends AppCompatActivity {
public static final String NOTIFICATION_CHANNEL_ID = "10001";
private final static String default_notification_channel_id = "default";
Button btnDate;
final Calendar myCalendar = Calendar.getInstance();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnDate = findViewById(R.id.btnDate);
}
// 지정한 시간(delay)에 알림을 발생시키도록 AlarmManager에 예약
private void scheduleNotification(Notification notification, long delay) {
Intent notificationIntent = new Intent(this, MyNotificationPublisher.class);
notificationIntent.putExtra(MyNotificationPublisher.NOTIFICATION_ID, 1);
notificationIntent.putExtra(MyNotificationPublisher.NOTIFICATION, notification);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
assert alarmManager != null;
// 실제 시각 기준 예약이므로 RTC_WAKEUP 사용
alarmManager.set(AlarmManager.RTC_WAKEUP, delay, pendingIntent);
}
// 알림 객체 생성
private Notification getNotification(String content) {
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this, default_notification_channel_id);
builder.setContentTitle("Scheduled Notification");
builder.setContentText(content);
builder.setSmallIcon(R.drawable.ic_launcher_foreground);
builder.setAutoCancel(true);
builder.setChannelId(NOTIFICATION_CHANNEL_ID);
return builder.build();
}
// 날짜 선택 리스너
DatePickerDialog.OnDateSetListener date = new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
myCalendar.set(Calendar.YEAR, year);
myCalendar.set(Calendar.MONTH, monthOfYear);
myCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
updateLabel();
}
};
// TextView 클릭 시 날짜 선택 다이얼로그 표시
public void setDate(View view) {
new DatePickerDialog(MainActivity.this, date,
myCalendar.get(Calendar.YEAR),
myCalendar.get(Calendar.MONTH),
myCalendar.get(Calendar.DAY_OF_MONTH)
).show();
}
// 선택된 날짜를 화면에 표시하고 알림 예약
private void updateLabel() {
String myFormat = "dd/MM/yy";
SimpleDateFormat sdf = new SimpleDateFormat(myFormat, Locale.getDefault());
Date date = myCalendar.getTime();
btnDate.setText(sdf.format(date));
scheduleNotification(getNotification(btnDate.getText().toString()), date.getTime());
}
}
동작 흐름 요약: 사용자가 TextView를 누르면 setDate()가 호출되어 날짜 선택 다이얼로그가 열리고, 날짜가 확정되면 updateLabel()이 실행됩니다. 이 메서드는 선택한 날짜를 화면에 표시하는 동시에, 해당 시각의 밀리초 값(date.getTime())을 scheduleNotification()에 전달해 알람을 예약합니다.
4단계: 알림 게시자 구현 (src/MyNotificationPublisher.java)
예약된 시간이 되면 시스템이 이 BroadcastReceiver를 호출하고, 여기서 실제 알림을 게시합니다. Android 8.0(API 26) 이상에서는 반드시 알림 채널을 먼저 생성해야 한다는 점에 유의하세요.
package app.tutorialspoint.com.notifyme;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import static app.tutorialspoint.com.notifyme.MainActivity.NOTIFICATION_CHANNEL_ID;
public class MyNotificationPublisher extends BroadcastReceiver {
public static String NOTIFICATION_ID = "notification-id";
public static String NOTIFICATION = "notification";
@Override
public void onReceive(Context context, Intent intent) {
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = intent.getParcelableExtra(NOTIFICATION);
// Android 8.0(Oreo) 이상에서는 알림 채널 필수
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel notificationChannel = new NotificationChannel(
NOTIFICATION_CHANNEL_ID, "NOTIFICATION_CHANNEL_NAME", importance);
assert notificationManager != null;
notificationManager.createNotificationChannel(notificationChannel);
}
int id = intent.getIntExtra(NOTIFICATION_ID, 0);
assert notificationManager != null;
notificationManager.notify(id, notification);
}
}
5단계: 매니페스트 설정 (AndroidManifest.xml)
리시버를 시스템에 등록하고, 진동 권한을 추가합니다. <receiver> 선언이 빠지면 알람이 울려도 알림이 표시되지 않으므로 반드시 확인하세요.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="app.tutorialspoint.com.notifyme">
<uses-permission android:name="android.permission.VIBRATE" />
<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/AppTheme">
<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=".MyNotificationPublisher" />
</application>
</manifest>
앱 실행 및 결과 확인
이제 앱을 실행해 보겠습니다. 실제 안드로이드 기기를 컴퓨터에 연결한 상태에서, Android Studio 툴바의 Run(실행) 아이콘을 클릭하고 대상 기기로 연결된 스마트폰을 선택합니다.
앱이 실행되면 화면의 TextView를 눌러 원하는 날짜를 선택하세요. 선택 즉시 해당 날짜가 표시되고 알림이 예약되며, 지정된 날짜가 되면 기기에 "Scheduled Notification"이라는 제목의 알림이 자동으로 나타납니다.
추가 팁 및 참고 사항
- 정확한 시간 보장: 절전(Doze) 모드 등의 제약 때문에 일반
set()은 약간 늦게 실행될 수 있습니다. 정확한 시점이 중요하다면setExactAndAllowWhileIdle()을 사용하세요. (Android 12 이상에서는SCHEDULE_EXACT_ALARM권한이 필요할 수 있습니다.) - 최신 프로젝트 환경: AndroidX 기반 프로젝트라면
android.support.v4.app.NotificationCompat대신androidx.core.app.NotificationCompat을 임포트하세요. - 대안: 반복 작업이나 네트워크 조건이 필요한 예약이라면
WorkManager를, 짧은 지연 후 실행이라면Handler.postDelayed()를 검토하는 것도 좋습니다.