【问题标题】:How to perfectly sync clock app widget with system clock in Android?如何在 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 秒。

【问题讨论】:

    标签: android android-intent android-widget android-manifest android-broadcast


    【解决方案1】:

    这是一个老问题,但在 Android Oreo 及更高版本上使用带有 ACTION_TIME_TICK 的 BroadcastReceiver 将不再适用。 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"/>
    

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

    【讨论】:

    • 它适用于日历吗?或者对于日历只需使用 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() 启动一个服务并更新小部件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-09
    相关资源
    最近更新 更多