【问题标题】:Time since first boot up自首次启动以来的时间
【发布时间】:2014-06-10 13:02:42
【问题描述】:

我正在开发一个 android 应用程序,并遇到了确定系统首次启动时间的问题。我的意思是我需要测量从设备首次启动到已经过去了多少时间

我知道侦听 ACTION_BOOT_COMPLETED 并将任何内容保存在 SharedPreferences 中的解决方案,但我需要另一个解决方案,因为这个解决方案在某些情况下不起作用。也许有任何系统属性?

用例(摘自discussion

  1. 我从服务器收到的每个文件的文件名都包含时间戳 取自System.currentMillis()
  2. 我比较这些时间戳以确定哪个文件是最新的。
  3. 现在,用户提前几个月更改系统时间。
  4. 我仍然能够确定用户更改系统时间后下载的最新文件。
  5. 现在,用户将时间更改回原始设置。
  6. 在比较时间戳时,第 4 步下载的文件总是胜出。

解决这个问题的灵丹妙药是一个时间戳,它计算自首次启动(出厂重置后)以来的秒数。就像SystemClock.elapsedRealtime(),但每次启动后都没有重置。不幸的是,到目前为止的答案告诉我们,这个灵丹妙药并不存在。

但是,许多答案显示了如何解决该问题的多种选择。 OneWorld123 评论了每个答案,这是否符合他的需求。

【问题讨论】:

  • 那么,为什么旧​​答案不能满足您的要求?
  • @hasan83 ozbeks 的回答并未涵盖“首次启动”这一事实。请参阅我的赏金说明。
  • @OneWorld,恐怕我没有更具体的解决方案,但您可以调查的是查看外部 SD 卡上文件/目录的时间戳 - 例如目录/sdcard/Android/ 是由 Android 系统创建的(我猜是在首次启动时?),因此您可以查看其上或其中的文件或其他系统创建的目录中的时间戳以确定日期/时间的时间设备首次启动(只要在第一次启动期间时钟正确)。不幸的是,我不知道这是否有效。
  • @JonasCz "...在外部 SD 卡上..." 如果设备在第一次启动时没有存储卡怎么办?如果外置 SD 卡在首次启动几年后首次插入会怎样?
  • @OneWorld 为什么你用用例更新了最初的问题?答案很好,但这不是我的用例。

标签: java android time clock system-clock


【解决方案1】:

也许有任何系统属性?

不确定系统属性,但有 SystemClock 类提供 API 以获取系统正常运行时间:

SystemClock.uptimeMillis()哪个

返回自启动以来的毫秒数,不计算深度睡眠所花费的时间

你也可以使用SystemClock.elapsedRealtime() which

返回自启动以来的毫秒数,包括睡眠时间

希望这会有所帮助。

【讨论】:

  • 感谢您的回复,但也许我没有明白,SystemClock.uptimeMillis() 或 SystemClock.elapsedRealtime() 是否提供从唯一的第一次启动或上次启动的时间?我需要的是,例如,当手机是新手机时,您第一次启动它并运行设置。 (另一种情况是进行出厂重置,它将使手机恢复初始状态)
  • 这些提供自上次启动以来的时间。
【解决方案2】:

如果需要知道第一次启动 Android 设备是什么时候

最简单的方法是拥有一个应用程序

  • 安装在出厂映像中
  • 配置为在引导期间运行
  • 在首次运行时将当前日期和时间记录到 sharedPreference

随后,任何其他需要确定 Android 设备首次启动时间的应用都可以在设备的生命周期内查找相应的sharedPreference。 (或直到设备恢复出厂设置;此时预安装的应用程序会在重启后将新的日期和时间写入共享首选项。)


但是,如果无法在 Android 设备上预安装应用程序,那么可能的解决方法是:

1。作为 root/超级用户

人们会查找已知在首次启动期间在 Android 设备上创建的目录/文件的时间戳。

2。作为常规应用,

使用标准 Android API 的一种简单解决方法是检查已知在首次启动期间安装的适当系统包的安装时间。

/* This returns the last time a package was installed */
PackageManager pm = context.getPackageManager();
PackageInfo pInfo = pm.getPackageInfo(<app-package-name>, 0);
return pInfo.firstInstallTime;

3。或者作为常规应用,

如果我们可以依赖在第一次启动期间一次性更新的特定包(并且永远不会再次更新),我们可以检查其更新时间如下:

/* This returns the last time a package was updated */
PackageManager pm = context.getPackageManager();
ApplicationInfo appInfo = pm.getApplicationInfo(<app-package-name>, 0);
String appFile = appInfo.sourceDir;
long installed = new File(appFile).lastModified();

【讨论】:

  • 不能生根。至于检查安装时间:听起来很有希望。然而,这使用了用户可以更改的“挂钟时间”。我必须将它与 System.currentMillis() 进行比较——我不想再使用这种方法了。
  • @OneWorld 您是否正在尝试实施某种过期的 DRM / 安全监控 / 有时限的许可证?此处关于 SO 的问题解释了您的实际用例可能会提出潜在的替代设计,而不是在第一次启动时进行修改。
  • 在此聊天chat.stackoverflow.com/rooms/102325/…中查看有关我的用例的讨论
  • @oneworld 对。上面的聊天讨论强调了对单调计数器的需求。您可以通过为您的数据的每个实例标记一个序列 ID 来实现这一点。有一个类/模块,每次调用它时都会返回唯一的递增整数。这与挂钟/时间戳是分开的。每次启动您的应用程序时,请记住在开始返回 ID 之前将计数器初始化为“最后一个最大的序列 ID + 1”。您还需要知道首次启动时间的任何其他原因?...
  • “单调”计数器将是解决该问题的最干净的方法。我将在未来的项目中实现这一点。
【解决方案3】:

如果我们坚持使用 SDK,我不知道有什么方法可以直接提供这些信息;但可能有一种方法可以从其他资源中获取这些信息。同样,如果我们坚持使用 SDK,一个“相当可靠”的选项是使用 Android 操作系统在设备生命周期内保存的application usage statistics。那就是 - 保存的第一个“使用统计信息”的时间戳。

不过,这显然没有提供准确的“首次启动时间”时间戳,因此这取决于您的情况是否可以使用某种近似值。一般来说,使用统计的问题在于,Andriod 会在很远的时间段内聚合它——所以,越旧的设备——日期越不准确。例如,对于我目前在 2014 年 12 月 3 日首次启动的手机,汇总的使用统计数据目前首次记录在 2014 年 12 月 21 日(记录在案 - 撰写本文时是 2016 年 2 月)。 (我不得不承认,虽然我不知道 Android OS 是如何安排聚合的,以及它是否只是安排在每年的 12 月 21 日,或者它是否确实有点接近第一次设备使用 - 我想这很容易与任何其他设备进行检查。)

以下是一些示例代码,显示了UsageStatsManager 的用法,但它肯定需要更多的调整,以解决在最近时期具有更高精度的事实:

UsageStatsManager usageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
Calendar year2013 = Calendar.getInstance(); year2013.set(2013, 0, 1);
List<UsageStats> stats = usageStatsManager.queryUsageStats(
    UsageStatsManager.INTERVAL_YEARLY, // or adjust for "younger" devices to get more precision - so, you'll probably need several queries
    year2013.getTimeMillis(),
    Calendar.getInstance().getTimeInMillis());
// now, first element in stats (if it is present at all) will point to the "earliest" statistics saved *for this interval* (yearly in this case)
// use UsageStats.getFirstTimeStamp() to get first known/saved usage

另请注意,如 SDK 中所述,UsageStatsManager 需要 PACKAGE_USAGE_STATS 系统级权限,因此您需要先让用户在“设置”中接受它:

Intent settingsIntent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(settingsIntent);

希望对你有帮助!

【讨论】:

  • UsageStatsManager 仅适用于 API 21+。
【解决方案4】:

根据您对 https://chat.stackoverflow.com/rooms/102325/discussion-between-ankitagrawal-and-oneworld 的讨论,您需要一个单调计数器来唯一标识数据集。

为此,您可以轻松设置 SharedPreference 并在每次需要新标识符时增加该值。当您需要知道哪个是最新文件时,只需比较标识符即可。如果卸载应用后该计数器被重置是一个问题,请参考:In android is there any way to preserve SharedPreferences after an uninstall

可以使用的另一种方法是从外部服务器请求时间戳。

希望对你有帮助 ;-)

【讨论】:

  • 讨论是关于不同的问题。我在询问完全重置后的时间戳,因此在这种情况下,用户空间中任何应用程序的共享首选项都不会被保存。
  • 好的,但是您可以将此首选项保存在云中,您可以通过备份将它们取回。或者您要求应用完全离线?
  • 顺便提一下,我不再参与那个项​​目了:) 我不记得确切的要求是什么,抱歉。但我同意这是可能的解决方案之一。而且我认为我们正计划将应用网络通信减少到最低限度。
【解决方案5】:

ANDROID SDK 中有 3 种方法用于这些:-

public static long  elapsedRealtime ()

在 API 级别 1 中添加

返回自启动以来的毫秒数,包括睡眠时间。 返回

自启动以来经过的毫秒数。

public static long elapsedRealtimeNanos ()

在 API 级别 17 中添加

返回自启动后的纳秒数,包括睡眠时间。返回

自启动以来经过的纳秒。

对于@oneWorld 案例:

您可以使用两种方法:-

1) 在写入时检查某些数据的日期是否高于当前日期,然后将先前数据的日期更改为小于当前数据和时间的日期, 所以它会返回正确的最新数据。

2)您可以将时间存储在服务器上并从那里检索时间并设置它。

【讨论】:

  • 请阅读我的赏金描述。我讨论了您在答案中发布的不适合解决问题的方法。
  • 我回答的是 user2857033 而不是你的特殊情况,无论如何我有一个适合你的解决方案
  • 你需要从用户第一次启动到现在的时间吗??
  • 自首次启动以来的时间:- 每当用户关闭手机时存储 SystemClock.elapsedRealtime() 和 sharePreference 中的当前日期和时间以及何时打开检查当前日期和时间以及从 sharedPreference 到获取手机关机的时间,并且你在 SystemClock.elapsedRealtime() 中首次启动,所以你可以使用这种方法来获取经过的时间
  • 在用户关闭手机时存储当前的 elapsedRealtime 可以解决问题。但是,这不是一种稳健的方法。如何检测,设备正在关闭?如果我的应用在关闭前崩溃了怎么办?另请参阅我对该问题的最新评论。
猜你喜欢
  • 2010-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-03
  • 1970-01-01
相关资源
最近更新 更多