- 캘린더형 위젯을 지원 중인데, 자정이 지나도 위젯이 갱신되지 않고 전날 날짜가 그대로 유지되는 현상이 발견되었다.
- 자정이 되는 시점을 감지하고, 위젯을 update 시켜주는 로직 구성 작업이 필요했다.
- 안드로이드 4대 컴포넌트 중 하나인 BroadcaseReceiver를 사용하면 된다.
What are the four components of an android application?
- Activities
- Services
- Broadcast Receivers
- Content Providers
- 자정 시간을 알람 시간으로 등록하고 해당 시간이 되면 PendingIntent를 통해 리시버를 동작시킨다.
class MidNightReceiver: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Intent intent = new Intent(context, WidgetProvider.class);
intent.setAction("android.appwidget.action.APPWIDGET_UPDATE");
context.sendBroadcast(intent);
}
}
- onReceive에는 자정에 갱신할 위젯의 갱신 로직을 구성해 주면 된다.
- AppWidgetProvider를 상속받는 각 WidgetProvider에서 onUpdate 시, PendingIntent를 등록한다.
- (보통 Widget이 여러개면 공통 동작을 구성하기 위해 abstract로 상위 Provider를 구성하고, 채택하는 방식으로 가는 것도 좋습니다.)
abstract class AbstractAppWidgetProvider : AppWidgetProvider() { ... }
- PendingIntent를 등록하는 함수와, 이미 지정한 Receiver에 대한 PendingIntent가 등록되어 있는지 검사하는 함수를 구성
private fun scheduleMidnightRefresh(context: Context) {
if (isMidnightRefreshScheduled(context)) return
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, MidNightReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val calendar = Calendar.getInstance().apply { add(Calendar.DAY_OF_YEAR, 1) }
CalendarUtil.setCalendarTime0(calendar)
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, pendingIntent)
}
private fun isMidnightRefreshScheduled(context: Context): Boolean {
val intent = Intent(context, MidNightReceiver::class.java)
return PendingIntent.getBroadcast(
context, 0, intent, PendingIntent.FLAG_NO_CREATE or PendingIntent.FLAG_IMMUTABLE
) != null
}
- FLAG_NO_CREATE 같은 경우에는 현재 등록된 PendingIntent가 있으면 반환하고, 없으면 null을 반환한다.
- PendingIntent가 등록되어 setExact로 실행되지 않는 이상 소멸되지 않기 때문에 null check를 통해 불필요한 등록 요청을 방지할 수 있다.
- 만일 PendingIntent가 정상적으로 울리면 곧바로 위젯 갱신과 동시에 onUpdate에서 scheduleMidnightRefresh() 함수를 호출하여 재등록될 것이다.
open fun updateWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int,
remoteViews: RemoteViews?,
) {
scheduleMidnightRefresh(context)
.....