如何在 Android 中完美同步时钟应用程序小部件与系统时钟?

How to perfectly sync clock app widget with system clock in Android?

我制作了一个数字时钟小部件,它使用 AlarmManager 每 60 秒更新一次时间。

@Override
public void onEnabled(Context context) {
    super.onEnabled(context);
    Log.d("onEnabled","Widget Provider enabled.  Starting timer to update widget every minute");
    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    alarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis(), 60000, createClockTickIntent(context));
}

问题是,每 60 秒轮询一次系统时间不会使我的小部件时间与系统时间同步。假设用户在 6:00:20 添加小部件,我的小部件显示时间 6:00 并休眠 60 秒,因此当系统时间变为 6:01:00 时,我的小部件需要另外 20 秒才能赶上。

有没有办法做到以下几点?

  • step 1: get system time and show on widget.

  • step 2: set the first update interval = (60 - current Seconds value).

  • step 3: after first update, set the subsequent update intervals to 60 seconds.

拦截 ACTION_TIME_TICK 广播。此广播操作在本地时区时钟每分钟更改时发送一次。

private BroadcastReceiver receiver;

@Override
public void onEnabled(Context context)
{
    super.onEnabled();
    receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context ctx, Intent intent)
        {
            if (intent.getAction().compareTo(Intent.ACTION_TIME_TICK) == 0) {
                // update widget time here using System.currentTimeMillis()
            }
        }
    };

    context.getApplicationContext().registerReceiver(receiver, new IntentFilter(Intent.ACTION_TIME_TICK));
}

@Override
public void onDisabled(Context context)
{
    super.onDisabled();
    if (receiver != null)
        context.getApplicationContext().unregisterReceiver(receiver);
}

进一步考虑:

  • 我们可以尝试在 AppWidgetProvider class' onReceive() 方法中捕获 ACTION_TIME_TICK 广播(在将操作添加到 intent-filter 之后清单),但文档指出此广播操作只能被以编程方式注册的 BroadcastReceiver 拦截。不过,这可能值得一试。
  • 并不是说使用 BroadcastReceiver 比使用 AlarmManager 更 "better"。不同的情况需要不同的方法,既然ACTION_TIME_TICK广播是由系统发送的,为什么不利用它呢?

这是一个老问题,但是在 Android Oreo 及更高版本上将 BroadcastReceiver 与 ACTION_TIME_TICK 一起使用将不再有效。 API 级别 17+ 的更好替代方法是使用 RemoteViews 支持的 TextClock。只需在您的时钟小部件布局中添加如下内容:

<TextClock
        android:id="@+id/widget_clock"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="56sp"
        tools:text="12:45"
        <!-- You can also easily add custom typefaces -->
        android:fontFamily="@font/quicksand_regular"
        android:textColor="@color/white"/>

时钟应自动与系统时钟同步。