320x100
특정 시간, 날짜 등 시간을 기준으로 하여
알림을 울리는 작업을 하고자 한다
사실 AlarmManager 만 있는건 아니지만
도즈모드의 문제 때문에 AlarmManager 를 선택했다
도즈모드에 대해서는 아래
android 공식문서에서 확인 하면 될 듯 싶다
https://developer.android.com/training/monitoring-device-state/doze-standby
이번에는 사용자가 특정 날짜를 기입함으로써
기입한 날짜에 알림을 울리게 해봤다
BroadcastReceiver로 받고 알림을 울리기 때문에
어플을 끈 상태이거나, 화면이 꺼져 있더라도
알림이 울리며,
도즈모드에서도 울리게 되어 있으니
대기 시간이 길더라도 울릴 것으로
확인된다
코드 1 : MainActivity.kt
아래 코드에서 주의 할 점이 있는데
이번 코드의 알람매니저의 경우 RTC 기준으로 시간을 잡았으며,
버전마다 사용하는 함수가 틀리므로
지원범위를 생각해서 코드를 작성하면 될 것 같다
class MainActivity : AppCompatActivity() {
private lateinit var edYMD: EditText
private lateinit var edHMS: EditText
private lateinit var bAlarmStart: Button
private lateinit var bAlarmCancel: Button
private lateinit var tvMsg: TextView
private lateinit var alarmManager: AlarmManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
edYMD = findViewById(R.id.et_ymd)
edHMS = findViewById(R.id.et_hms)
bAlarmStart = findViewById(R.id.b_alarmStart)
bAlarmCancel = findViewById(R.id.b_alarmCancel)
tvMsg = findViewById(R.id.tv_msg)
// 알림 매니저 객체 가져오기
alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager
bAlarmStart.setOnClickListener { alarmStart() }
bAlarmCancel.setOnClickListener { alarmCancel() }
}
// 년월일, 시분초 확인 후 알림 등록
private fun alarmStart() {
if(edYMD.text.length != 8) { // 년월일 확인
tvMsg.text = "년월일 8자리의 범위를 확인해 주세요"
} else if(edHMS.text.length != 6) { // 시분초 확인
tvMsg.text = "시분초 6자리의 범위를 확인해 주세요"
} else { // 알림 등록 시작
val calendar = getCalendar(edYMD.text.toString(), edHMS.text.toString())
calendar?.let {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
getPendingIntent()
)
} else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
getPendingIntent()
)
} else {
alarmManager.set(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
getPendingIntent()
)
}
tvMsg.text = "알림 등록을 완료하셨습니다"
}
}
}
// 입력한 년월일, 시분초에 따라 calendar 작성
private fun getCalendar(ymd: String, hms: String): Calendar? {
val calendar = Calendar.getInstance()
val simpleDateFormat = SimpleDateFormat("yyyyMMdd kkmmss", Locale.KOREA)
val date = simpleDateFormat.parse("$ymd $hms")
try {
calendar.time = date
} catch (e: Exception) {
e.printStackTrace()
return null
}
return calendar
}
// 등록한 알림 삭제
private fun alarmCancel() {
alarmManager.cancel(getPendingIntent())
tvMsg.text = "알림을 취소하셨습니다"
}
// api 버전에 따라 PendingIntent 가져오기
private fun getPendingIntent(): PendingIntent {
val intent = Intent(this, AlarmReceiver::class.java)
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.getBroadcast(
this, AlarmReceiver.ALARM_ID, intent,
PendingIntent.FLAG_MUTABLE
)
} else {
PendingIntent.getBroadcast(
this, AlarmReceiver.ALARM_ID, intent,
PendingIntent.FLAG_UPDATE_CURRENT
)
}
}
}
코드 2 : AlarmReceiver.kt
class AlarmReceiver : BroadcastReceiver() {
companion object {
const val ALARM_ID = 0
const val NOTIFICATION_CHANNEL = "test_real_alarm_notification"
}
private lateinit var notificationManager: NotificationManager
override fun onReceive(context: Context, intent: Intent) {
// 알림 매니저
notificationManager = context.getSystemService(
Context.NOTIFICATION_SERVICE) as NotificationManager
notificationShow(context)
}
private fun notificationShow(context: Context) {
createNotificationChannel()
// 알림 생성
val builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("Alarm Notification Title")
.setContentText("알림이 도착하였습니다")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
.setDefaults(NotificationCompat.DEFAULT_ALL)
// 알림 호출
notificationManager.notify(0, builder.build())
}
// 채널 생성 - 오레오 버전 이상 부터
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationChannel = NotificationChannel(
NOTIFICATION_CHANNEL,
"Stand up notification",
NotificationManager.IMPORTANCE_HIGH
)
notificationChannel.enableLights(true)
notificationChannel.lightColor = Color.RED
notificationChannel.description = "Notification Test"
notificationManager.createNotificationChannel(
notificationChannel)
}
}
}
코드 3 : 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" >
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_ymd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginTop="5dp"
android:text="[년월일 8자리 (예 : 20220101)]"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/et_ymd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="20dp"
android:ems="10"
android:hint="년월일 8자리를 입력해 주세요"
android:inputType="number"
android:textAlignment="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_ymd" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp">
<TextView
android:id="@+id/tv_hms"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginTop="5dp"
android:text="[시분초 6자리 (예 : 153020)]"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/et_hms"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="20dp"
android:ems="10"
android:hint="시분초 6자리를 입력해 주세요"
android:inputType="number"
android:textAlignment="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_hms" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="10dp"
android:paddingTop="10dp"
android:paddingEnd="10dp"
android:paddingBottom="10dp">
<Button
android:id="@+id/b_alarmStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="알림 설정" />
<Space
android:layout_width="10dp"
android:layout_height="wrap_content" />
<Button
android:id="@+id/b_alarmCancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="알림 취소" />
</LinearLayout>
<TextView
android:id="@+id/tv_msg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="none"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
</LinearLayout>
320x100
'Android > Kotlin' 카테고리의 다른 글
[Android][Kotlin] 단말기(device) 가로 세로 실제 해상도 가져오기 (0) | 2022.10.21 |
---|---|
[Android][Kotlin] Thread 에러 처리 및 UI 변경 활용 예제 (0) | 2022.10.20 |
[Android][Kotlin] 알림(Notification) 생성, 호출하기 (0) | 2022.10.13 |
[Android][Kotlin] 캘린더(CalendarView) 생성, 오늘 날짜, 클릭 이벤트 (0) | 2022.10.12 |
[Android][Kotlin] Thread 상속 받고 Thread 일시정지 (0) | 2022.10.07 |