现在有一个需求:Android设备在开机的时候统计开机时间,然后上报至服务器。一般来说我们都是这样做的:

在开机广播里,调用System.currentTimeMillis()获取开机时的时间戳,然后将其上报至服务器。

可是有一个问题不知道你有没有想过:

如果此时这个Android设备的系统时间与标准北京时间相比不准确呢?
假如现在北京时间是2016年12月2日 17:00:00,那么转换为时间戳是1480669200(单位:秒),而此Android设备的系统时间为2016年1月1日 8:00:00,那么获取的时间戳为1451606400(单位:秒),你总不能把这个时间戳给上报至后台服务器吧?

要想解决这个问题,得先知道下面这个方法。

  • elapsedRealtime() 此方法为Android特有的类SystemClock里面的一个方法,先看一下官方文档给的解释:
/**
 * Returns milliseconds since boot, including time spent in sleep.
 *
 * @return elapsed milliseconds since boot.
 */
native public static long elapsedRealtime();

翻译过来就是——此方法可以获取Android设备的开机时长,包括睡眠时间,也就是说调用此方法可以获取设备开机时到调用此方法时的完整时间。注意:此方法是与时间戳无关的,不管设备系统在这个时间段是否更新校验时间。

那么我们知道了这个方法后,应该怎么用起来呢?其实很简单,当设备开机后,将开机时间戳startTime记录下来,然后从网络获取标准的北京时间的时间戳standardTime,用此时间戳standardTime减去该设备的开机时长elapsedRealtime(),那么此时得到一个新的时间戳就是开机时的时间戳newStartTime,再用此时间戳newStartTime和之前记录的开机时间戳startTime比较,如果误差大于1分钟(一般来说设备通电开机到发送开机广播是有几十秒的,该时间会被统计到开机时长中),那么就将新的开机时间戳newStartTime上报至服务器,这样可以解决文章开头提到的问题,除非设备一直不联网,那这样谁也没办法啦~具体代码如下:

  1. 在开机广播中获取开机时间戳
// 一般将此时间戳保存下来以便后面校验,推荐用SharedPreferences保存
// 文章末尾贴出了SharedPreferences的工具类,有需要的可以看看
long startTime = System.currentTimeMillis();
SharePreferenceUtils.newInstance(context).setLong("startTime", startTime);
  1. 从网络获取标准北京时间的时间戳
// 获取网络时间
public static long getNetTime() {
    long standardTime;
    try {
        //取得资源对象,网址可替换
        URL url = new URL("http://www.baidu.com");
        //生成连接对象
        URLConnection uc = url.openConnection();
        //发出连接
        uc.connect(); 
        //取得网站日期时间
        standardTime = uc.getDate(); 
        return standardTime;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return 0;
}
  1. 校验开机时间戳
// 校验开机时间戳
public static void checkBootTime() {
    // 获取开机时长
    long runTime = SystemClock.elapsedRealtime();
    // 获取开机时间戳
    long bootTime = SharePreferenceUtils.newInstance(context).getLong("startTime", 0);
    // 获取新的开机时间戳
    long newBootTime = getNetTime() - runTime;
    if (newBootTime - bootTime > 1 * 60 * 1000) {
        bootTime = newBootTime;
    }
    // 此处可以上报校验后的开机时间戳bootTime
    ...
}

以上就是更新校验开机的时间戳全部思路过程和代码。