System.currentTimeMillis()
和 SystemClock.elapsedRealtime()
在 Android 开发中用于不同的时间测量场景,核心区别在于它们的底层实现和对系统时间变化的敏感度。以下是详细说明和代码示例:
1. System.currentTimeMillis()
- 定义:返回自 1970 年 1 月 1 日 UTC 以来的毫秒数(Unix 时间戳)。
- 特点 :
- 受系统时间设置影响(用户或网络时间同步可能导致时间跳变)。
- 设备休眠时不会递增。
- 适用场景:需要与真实时间相关的操作,如记录事件时间、生成日期字符串等。
代码示例:记录事件时间戳
java
// 记录用户点击事件的时间
long clickTime = System.currentTimeMillis();
saveToDatabase("User clicked at " + clickTime);
// 将时间戳转换为可读日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
String dateStr = sdf.format(new Date(clickTime));
Log.d("EventTime", "点击时间: " + dateStr);
2. SystemClock.elapsedRealtime()
- 定义:返回自设备启动以来经过的毫秒数(包括深度休眠时间)。
- 特点 :
- 不受系统时间设置影响。
- 设备休眠时仍会累计时间。
- 适用场景:测量时间间隔(如性能统计、倒计时),需稳定不受系统时间干扰的场景。
代码示例:测量代码执行时间
java
// 开始计时
long startTime = SystemClock.elapsedRealtime();
// 模拟耗时操作(如下载文件)
new Thread(() -> {
try {
Thread.sleep(2000); // 模拟 2 秒操作
} catch (InterruptedException e) {
e.printStackTrace();
}
// 计算实际耗时
long endTime = SystemClock.elapsedRealtime();
long duration = endTime - startTime;
Log.d("Performance", "操作耗时: " + duration + " 毫秒");
}).start();
错误用法示例
错误:使用 System.currentTimeMillis()
计算耗时
java
long start = System.currentTimeMillis();
// 假设用户在此期间调整了系统时间
Thread.sleep(5000); // 实际耗时 5 秒
long end = System.currentTimeMillis();
long wrongDuration = end - start; // 可能得到负数或极大值
正确:使用 SystemClock.elapsedRealtime()
java
long start = SystemClock.elapsedRealtime();
Thread.sleep(5000);
long end = SystemClock.elapsedRealtime();
long correctDuration = end - start; // 始终准确为 ~5000 毫秒
总结对比表
特性 | System.currentTimeMillis() |
SystemClock.elapsedRealtime() |
---|---|---|
时间基准 | Unix 时间戳(1970 年) | 设备启动后经过的时间 |
系统时间敏感 | ✔️(用户修改时间会影响结果) | ❌(结果稳定,不受时间设置影响) |
休眠时递增 | ❌(休眠时暂停) | ✔️(持续计时,包括休眠) |
典型用途 | 日历事件、日志时间戳 | 性能统计、倒计时、间隔测量 |
高级场景:跨进程时间同步
在需要跨组件(如 Service
和 Activity
)同步时间的场景中,elapsedRealtime()
更可靠。例如,音乐播放器显示播放进度:
java
// Service 中记录播放开始时间
long playbackStartTime = SystemClock.elapsedRealtime();
// Activity 中实时计算已播放时长
long currentElapsed = SystemClock.elapsedRealtime();
long playbackDuration = currentElapsed - playbackStartTime;
updateUI("已播放: " + playbackDuration + " 毫秒");
通过理解两者的差异,可以在不同场景中选择合适的 API 确保时间逻辑的准确性。