【问题标题】:Android exact Alarm is always 3 minutes offAndroid 精确闹钟总是关闭 3 分钟
【发布时间】:2015-12-03 19:53:08
【问题描述】:

我有一个应用程序,它使用AlarmManager 定期在整点唤醒手机并向 Android Wear 手表发送一条消息,该手表会产生短暂的振动。我有两个用户,他们的三星 Galaxy S6 和 5.1.1 的三星 Galaxy S6 和 5.1.1 的索尼 SW 3 遇到了一个奇怪的错误。在第一个整小时,振动是准确的时间,但所有其他振动都延迟了 3 分钟。有时甚至第一个整小时的振动也会延迟。

这是一些代码:

final Calendar time = Calendar.getInstance();
time.set(Calendar.SECOND, 0);
time.set(Calendar.MILLISECOND, 0);
time.set(Calendar.MINUTE, 0);
time.set(Calendar.HOUR_OF_DAY, time.get(Calendar.HOUR_OF_DAY) + 1);

final Intent hourlyChimeIntent = new Intent(context, HourlyChimeReceiver.class);
hourlyChimeIntent.setAction(key);
final AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
final PendingIntent pi = PendingIntent.getBroadcast(context, 0, hourlyChimeIntent, PendingIntent.FLAG_CANCEL_CURRENT);
am.setExact(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), pi);

我在接收器中获取WakeLock,然后在线程中向 Wear 手表发送消息。没有错过任何振动,他们只是迟到了 3 分钟。

我没有关于此问题的其他报告,我的所有测试设备都运行良好。不过我没有三星设备。

任何想法可能导致 3 分钟延迟?三星会忽略setExact 并让我的闹钟不准确吗?如何强制三星发出准确的警报?

编辑:

这是 Android Wear 特定代码。在接收者的onReceive 方法中,我这样做:

final PowerManager mgr = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
final PowerManager.WakeLock lock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, BuildConfig.APPLICATION_ID);
lock.acquire(7L * 1000L);

final GoogleApiClient googleApiClient = new GoogleApiClient.Builder(context).addApi(Wearable.API).build();

new Thread(new Runnable() {
    @Override
    public void run() {
        googleApiClient.blockingConnect();

        long pattern[];
        pattern = new long[] {0L, 500L};

        final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await(2000L, TimeUnit.MILLISECONDS);

        if (nodes != null) {
            for (final Node node : nodes.getNodes()) {
                // just send and forget
                Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), "/hourly_chime", Utils.Vibrator.serializeVibratePattern(pattern).getBytes()).await();
            }
        }
    }
}).start();

【问题讨论】:

  • 一个想法:也可能是警报按时发送,但稍后在某个地方引入了延迟。由于您的问题没有具体说明,我会问:您确定实际的警报传递延迟了吗?
  • 嗯,想一想,我不能 100% 确定这是警报传递。我怀疑打开与 Wear 设备的连接可能需要长达三分钟或通过蓝牙发送 Wear 消息。我会将 Wear 特定代码添加到问题中。
  • 我有同样的问题,当我希望我的应用程序在每个星期日的 18 点更新,但它没有完成工作,有时它没有工作,有时它被延迟,我不知道是谁在谷歌做这项工作,但它做错了,我认为是意图 [目的:)]
  • 我仅在三星设备上报告了此问题。在很多情况下,三星更改了一些核心功能以“优化”它,并在它在纯 Android 中运行时破坏它。

标签: android alarmmanager wear-os


【解决方案1】:

此问题似乎仅出现在带有 Lollipop(5.0、5.1、5.1.1)的三星设备(例如 Galaxy Grand、S4、S5、S6、Note 3、Note 4)上。当设备使用电池且屏幕关闭时,警报的安排似乎不准确。如果设备在计划警报期间正在充电或屏幕开启,则不会出现此问题。

您可以通过以下方式验证下一个警报是否不准确:

adb shell dumpsys alarm

我没有为这个问题找到完美的解决方案 - 只有解决方法,每个都有一些缺点:

  1. 使用setAlarmClock 代替setExact(请参阅this answer)。这很好用(不是在所有设备上),但这个解决方案的问题是警报会通过在状态栏中显示警报图标(如果有人还没有设置闹钟)和显示下一个闹钟预定时间来影响系统在警报小部件等上。不幸的是,虽然这适用于 5.1.1 的 Galaxy Grand,但它不适用于 5.0.1 的 Galaxy S4。
  2. 在安排警报之前启用屏幕(我在安排下一个警报之前执行此半秒以避免竞争条件)。当然,不是每个应用都启用屏幕只是为了安排下一个闹钟。
  3. 一个bug report describing similar issue用app包名长度连接!我没有验证它是否真的解决了这个问题,因为更改包名称不是已发布应用的选项。
  4. another report 有人声称可以使用 WakefulBroadcastReceiver 解决此问题,但在我的情况下不起作用。

顺便说一句,这个问题让我抓狂:)

编辑:当应用程序包名称中包含关键字“alarm”或“alert”时,似乎不会发生此问题(正如 Mathieu H. 在下面的 cmets 中指出的那样)。 p>

我还可以通过在电池设置(或智能管理器应用)中禁用应用优化来手动解决此问题。似乎无法以编程方式完成,因此您可以尝试询问您的用户...

【讨论】:

  • 感谢您提供如此精彩的信息。看起来像是三星的另一个伟大的“优化”。它还解释了为什么第一个警报准时而所有其他警报都延迟了。我可以使用的唯一解决方案是开屏。我会报告结果。
  • @PawełNadolski 关于第 2 项(在安排之前启用屏幕...),您如何打开屏幕以及如何提前半秒安排它?可以分享一下代码 sn-p 吗?
  • 我能够通过确保以小于 15 秒的间隔触发警报来解决此问题。奇怪的。例如,我的一个警报(每 10 秒)正确触发,但 60 秒警报不正确。因此,当 10s 警报触发 6 次时,我启动了 60s 服务。初步结果看起来是积极的。
  • 关于包名长度(第3点),假设几乎是正确的。经过多次测试,我注意到如果包名包含“alarm”或“alert”,那么AlarmManager会在完美的时机触发警报。获得电池寿命似乎是三星的坏招。这适用于我测试的所有设备,而 setAlarmClock 则不适用于 S4。
  • 为了找到其他解决方案,我开始检查三星框架。实际上还有更多可能的包名称模式,例如“时钟”... Smali 代码:pastebin.com/J1XjXxxw 我将继续寻找更好的解决方案,但它很难阅读 SMALI 代码并且转换器无法正常工作
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多