我正在开发一个android应用程序,并遇到了确定系统首次启动时间的问题。我的意思是,我需要测量从设备首次启动开始已经过了多少时间。
我知道监听ACTION_BOOT_COMPLETED并在SharedPreferences中保存任何内容的解决方案,但我需要另一个解决方案,因为这个解决方案在某些情况下不起作用。也许有什么系统属性?
用例(摘录自讨论)
- 我从服务器收到的每个文件的文件名都包括一个时间戳取自
System.currentMillis()
- 我比较这些时间戳,以确定哪个文件是最新的
- 现在,用户提前几个月更改系统时间
- 我仍然能够确定在用户更改系统时间后下载的最新文件
- 现在,用户将时间更改回原始设置
- 在比较时间戳时,在第4步下载的文件总是获胜
解决这个问题的灵丹妙药是一个自第一次启动(出厂重置后)起计算秒数的时间戳。就像SystemClock.elapsedRealtime()
一样,但每次启动后都没有重置。不幸的是,到目前为止的答案告诉我们,这颗银弹并不存在。
然而,许多答案显示了如何解决这个问题的多种选择。OneWorld123评论了每一个答案,这是如何满足他的需求的。
也许有什么系统属性?
不确定系统属性,但有SystemClock
类提供API以获得系统正常运行时间:
SystemClock.uptimeMillis()
哪个
返回自启动以来的毫秒数,不计算在深度睡眠中花费的时间。
您也可以使用SystemClock.elapsedRealtime()
哪个
返回自启动以来的毫秒数,包括睡眠时间。
希望这能有所帮助。
如果需要知道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();
如果我们坚持使用SDK,我不知道有什么方法可以直接提供这些信息;但是可能有一种方法可以从其他资源中获得该信息。同样,如果我们坚持使用SDK,一个"相当可靠"的选项是使用Android操作系统在设备使用寿命期间保存的应用程序使用统计数据。也就是说,保存的第一个"使用情况统计数据"的时间戳。
不过,这显然没有提供确切的"第一次启动时间"时间戳,因此这取决于在您的情况下是否可以进行某种近似。一般来说,使用情况统计数据的问题是,Andriod会将其聚合到一段遥远的时间内-因此,设备越旧-日期就越不准确。例如,对于我目前的手机,它于2014年12月3日首次启动,聚合使用情况统计数据目前首次记录在2014年12日21日(记录在案-在撰写本文时是2016年2月)。(但我不得不承认,我不知道安卓操作系统是如何安排聚合的,也不知道它是否只是安排在每年的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);
希望它能有所帮助!
根据您对以下内容的讨论:https://chat.stackoverflow.com/rooms/102325/discussion-between-ankitagrawal-and-oneworld,您需要一个单调计数器来唯一标识数据集。
为此,您可以轻松地设置SharedPreference,并在每次需要新标识符时增加该值。当您需要知道哪个是最新的文件时,只需比较标识符即可。如果这个计数器在应用程序卸载后重置是一个问题,请参阅:在android中,有没有任何方法可以在卸载后保留SharedPreferences
可以使用的另一种方法是从外部服务器请求时间戳。
希望有帮助;-)
ANDROID SDK中有三种方法:-
public static long elapsedRealtime ()
添加在API 1级中
返回自启动以来的毫秒数,包括睡眠时间。返回
自启动以来经过的毫秒数。
public static long elapsedRealtimeNanos ()
添加在API 17级中
返回自启动后的纳秒,包括睡眠时间。返回
自启动以来经过的纳秒。
对于@oneWorld案例:
你可以使用2种方法:-
1) 在写入时检查某些数据的日期是否高于当前日期,然后将以前数据的日期更改为小于当前数据和时间的日期,因此它将返回正确的最新数据。
2) 您可以将时间存储在服务器上,并从中检索时间并进行设置。