【问题标题】:Is there a way to detect when the user has changed the clock time on their device?有没有办法检测用户何时更改了设备上的时钟时间?
【发布时间】:2013-03-21 10:30:59
【问题描述】:

有没有办法在 Android 中检测 Android 系统时钟何时被用户重置?

我正在设计一个应用程序,它使用系统时间来确定用户何时在某个时间到达某个地点,并且我不想依赖那时的网络可用性。显然,因此最好知道用户何时更改了系统时钟,这样他们就不能“作弊”。

【问题讨论】:

    标签: android time


    【解决方案1】:

    是的,有。 ACTION_TIME_CHANGED Intent 在设备时间改变时广播,你可以有一个方法在检测到这个 Intent 时触发。

    此 Intent 自 API 级别 1 起就已在 Android 中使用,因此它应该适用于您可能需要兼容的任何平台。

    您需要使用BroadcastReceiver 处理广播:

    public class TimeChangedReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            //Do whatever you need to
        }
    
    }
    

    您还需要在清单中添加类似的内容:

    <receiver android:name=".TimeChangedReceiver">
      <intent-filter>
        <action android:name="android.intent.action.TIME_SET" />
      </intent-filter>
    </receiver>
    

    这将使 Android 知道在检测到此类意图时触发您的接收器。

    这似乎与谁编辑时间无关,但也不会在您与网络同步时触发自动调整。但是,如果您丢失网络并重新获得它,这可能会触发,因为您的时间会略有不同(假设您使用的是自动网络时间)。

    但是,根据我的经验,虽然手机上的时钟不是特别准确(因为它们通常依赖于与接收到的时间信号同步),但它们绝对不应该超过大约 30 秒或每小时分钟,绝对最大值,所以如果时间变化很小,你也许可以假设它是自动的。添加闰秒时,也可能会产生时间更改消息,尽管这些显然很小且不常见。

    您可以使用ConnectivityManager来跟踪手机是否有连接,您可以根据它更改行为(即只要有网络连接,并且时间是自动/网络时间,忽略时间变化或其他东西),但我找不到任何关于丢失/恢复网络连接的意图,所以你可能不得不使用轮询方法。

    【讨论】:

    • 此方法是否区分用户更改时间和因网络更新而更改时间?
    • 这是一个很好的问题。答案似乎是否定的,因为当我将手机置于飞行模式几分钟然后重新打开收音机时,它确实触发了。但是,当您从网络获取自动时间更新时,它似乎不会触发,并且会对其进行细微调整以保持时间准确。有几个选项可以获得非常准确的时间:您可以使用位置对象上的时间戳,它非常准确但不能按需请求(您可以听他们进来,当他们进来时,您会知道时间那时)。
    • 请参阅stackoverflow.com/a/12320918/1003511,了解从该位置获取时间的可能实现。似乎还有一种方法可以启用设备的自动时间同步设置,但如果用户出于某种原因手动设置了时间,这对您的用户来说可能不是最好的选择。有关这方面的更多信息,请参阅stackoverflow.com/a/8214204/1003511。我还编辑了我的答案。
    • 顺便说一句,您可以注册BroadcastReceiver 以更改连接性,我想?
    • 我在文档中寻找有关连接性的广播意图,但没有看到任何内容。不过,我可能会错过他们。您指的是哪些具体意图?
    【解决方案2】:

    如果用户调整时钟,系统时间 (System.currentTimeMillis()) 会改变,但自启动后经过的时间 (SystemClock.elapsedRealtime()) 希望不会。通过跟踪这两者之间的差异,可以检测到用户对系统时钟的重大更改。

    重要的是不要跟踪可能由网络更新系统时钟引起的微小变化。我将假设出于我的目的,大约半小时内的任何更改都无关紧要。系统时间不应随着Locale 国家/地区的变化而变化,但这也可能值得消除。

    经过的实时显然会在启动时重置,所以我应该包含一个BroadcastReceiver 以在接收到android.intent.action.BOOT_COMPLETED 时重置差异。

    【讨论】:

    • 我们不能不考虑 System.currentTimeMillis() 就直接使用 SystemClock.elapsedRealtime()
    • 这个答案很有帮助...SystemClock.elapsedRealtime() 在涉及时间计算的用例中更好
    【解决方案3】:

    注意matt5784的答案:我发现在Android 4.1.2上intent action不可用,不知道这是适用于所有android版本还是只适用于我的。而不是

         "android.intent.action.ACTION_TIME_CHANGED"
    

    使用

         "android.intent.action.TIME_SET"
    

    【讨论】:

    • 根据documentation,常量名称为ACTION_TIME_CHANGED,常量值为android.intent.action.TIME_SET
    【解决方案4】:

    我们可以同时使用TIME_SETTIMEZONE_CHANGED

    <application
        ...>
    
        <receiver android:name=".TimeChangedReceiver">
            <intent-filter>
                <action android:name="android.intent.action.TIME_SET"/>
                <action android:name="android.intent.action.TIMEZONE_CHANGED"/>
            </intent-filter>
        </receiver>
    </application>
    

    TimeChangedReceiver.java

    public class TimeChangedReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "time change " + intent.getAction(), Toast.LENGTH_SHORT).show();
        }
    }
    

    【讨论】:

      【解决方案5】:

      如果您不介意您的应用程序在用户的时钟由于 *DT/*ST 偏移而更新的情况下进行作弊,偶尔与可以倒带时钟的 NTP 源同步时间,您自己的进程停止,您可以对系统时间实施“后续”检查,以便如果时间“倒退”,您会认为这是“作弊”。否则,您必须依赖服务器,这将是您“有效”时间的来源。即便如此,您的服务器时间也偶尔会倒退。

      【讨论】:

      • 其实我只是想到了一些事情:我可以测量System.currentTimeMillis()SystemClock.elapsedRealtime() 之间的差异,如果它的变化超过几分钟,我就知道有问题了。显然我必须在系统启动时重置它,但我可以为系统启动事件添加一个BroadcastReceiver。感谢您对自动时钟更新的提醒;我希望有一种方法可以仅检测用户更改,但我想不会!
      猜你喜欢
      • 2011-12-14
      • 1970-01-01
      • 2015-12-04
      • 2011-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-18
      • 2020-04-24
      相关资源
      最近更新 更多