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

Posted

技术标签:

【中文标题】如何在 Android 中将时钟应用小部件与系统时钟完美同步?【英文标题】:How to perfectly sync clock app widget with system clock in Android? 【发布时间】:2015-06-03 10:30:06 【问题描述】:

我制作了一个数字时钟小部件,它使用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 秒才能赶上。

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

第 1 步:获取系统时间并在小部件上显示。

第二步:设置第一次更新间隔=(60 - 当前秒值)。

第 3 步:第一次更新后,将后续更新间隔设置为 60 秒。

【问题讨论】:

【参考方案1】:

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

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

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

【讨论】:

它适用于日历吗?或者对于日历只需使用 textview? 如果我想分隔小时和分钟怎么办?例如小时有较大的字体,分钟有较小的字体? 对于日历,您需要将 set24HourFormat() 和 set12HourFormat() 设置为所需的日期格式。如果你想有不同的小时和分钟大小,你需要两个文本时钟,一个是 HH 格式,另一个是 mm(24 小时:分钟),并分别设置 textsize。【参考方案2】:

拦截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 类的onReceive() 方法中捕获ACTION_TIME_TICK 广播(在清单中将操作添加到intent-filter 之后),但文档指出此广播操作只能被拦截由BroadcastReceiver 以编程方式注册。不过,这可能值得一试。 并不是说使用BroadcastReceiver 比使用AlarmManager“更好”。在不同的情况下需要不同的方法,既然ACTION_TIME_TICK广播是系统发送的,为什么不利用呢?

【讨论】:

感谢 ZygoteInit,BradcastReceiver 是否比 AlarmManager 更适合时钟小部件? 我试过了——它运行了大约 10 分钟——但随后系统关闭了我的进程并停止工作...... :-( @DeNitE:这在我之前从事的应用小部件项目中非常适合我。如果你能详细解释你的问题,最好是在另一个问题中,我很乐意提供帮助...... :) @Y.S.我想我明白了——我做了一个服务来更新 START_STICKY 的小部件,以确保它不会被关闭。现在效果很好! :-) @SaharPournasseh 当您拦截动作时间滴答广播时,从 onReceive() 启动一个服务并更新小部件。

以上是关于如何在 Android 中将时钟应用小部件与系统时钟完美同步?的主要内容,如果未能解决你的问题,请参考以下文章

如何每分钟更新一个 Android 应用小部件

如何在应用小部件中为 Android AnalogClock 设置时间?

如何像闹钟小部件(时钟应用程序)一样显示小部件?

Android小部件如何从中获取小时和分钟的时间?

Android桌面小部件AppWidget开发

如何在 Android Studio 中为 Flutter 上的小部件测试进入调试模式?