Development/Android

[Android] 자정이 지나면 위젯 갱신하기 (feat. BroadcastReceiver)

SeungYong.Lee 2025. 3. 20. 11:34
반응형

- 캘린더형 위젯을 지원 중인데, 자정이 지나도 위젯이 갱신되지 않고 전날 날짜가 그대로 유지되는 현상이 발견되었다.

 

- 자정이 되는 시점을 감지하고, 위젯을 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)
    .....

반응형