Android 4.4

好消息是从4.4开始,安卓系统自带计步传感器了,这样就再也不用我们自己通过监测加速传感器、重力传感器的数值变化去实现计步功能了,而且谷歌做的相当省电。
当然坏消息就是我们在使用AlarmManager启动闹钟的时候,时间可能就不准了,而且设置重复闹钟也可能不灵了 ==。

计步功能

SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
SensorEventListener sensorEventListener = new SensorEventListener() {

    @Override
    public void onSensorChanged(SensorEvent event) {
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}
};

Sensor stepSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
sensorManager.registerListener(sensorEventListener, stepSensor, Sensor.TYPE_STEP_COUNTER, SensorManager.SENSOR_DELAY_UI);

其中,在onSensorChanged(SensorEvent event)函数中,event.values[0]表示从开机开始的第一次注册计步传感器到现在的累计步数,当然前提是不要调用
sensorManager.unregisterListener(sensorEventListener);,这样系统就会一直在后台运行计步功能。

PS:如果我们在很多个Activity或者Service里面都只有registerListener去注册计步传感器,而没有在他们Destroy的时候去调用unregisterListener注销传感器,那么,当传感器监测的数值发生变化的时候还是会去调用每个Listener中的onSensorChanged函数的,所以有的时候就会发生一些很莫名其妙的错误就是因为没有注销监听导致的,使得即使Activity或Service已经Destroy了,但是监听函数却还是有作用。如果我们需要后台一直运行计步功能,那么我们只要保留一个Listener没有被注销掉就好了,其他的使用完及时注销。

闹钟不准时

使用安卓系统自带的闹钟基本流程都是这样:
[S1].获取闹钟管理器
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

[S2].获取需要执行的活动的PendingIntent对象,通过调用其静态方法获得

PendingIntent.getActivity...
PendingIntent.getActivities...
PendingIntent.getService...
PendingIntent.getBroadcast...

[S3].通过AlarmManagerset方法可以指定在某时刻,或者是开机时间点之后的相对时刻来启动闹钟,就是执行PendingIntent对象中的内容。
可是从set函数的文档说明中可以看到:

Beginning in API 19, the trigger time passed to this method is treated as inexact: the alarm will not be delivered before this time, but may be deferred and delivered some time later. The OS will use this policy in order to “batch” alarms together across the entire system, minimizing the number of times the device needs to “wake up” and minimizing battery use. In general, alarms scheduled in the near future will not be deferred as long as alarms scheduled far in the future.

大概意思就是从Android 4.4开始,闹钟就变得不准时了,这样做的目的是为了减少因为频繁唤醒设备所带来的电量消耗,不过可以保证的一点就是,我们设置的闹钟只会晚于我们设定的时间去启动,而不会早于。

这也就是为什么闹钟不去准时启动的原因。

闹钟重复有问题

然而闹钟不准时却不仅仅如此。

AlarmManager里面有一个很好的方法就是setRepeating,这个方法顾名思义就是去设置一个循环重复启动的闹钟,每隔一定的时间间隔去启动。

但是,在该方法的说明里又看到了这样的内容:

as of API 19, all repeating alarms are inexact. If your application needs precise delivery times then it must use one-time exact alarms, rescheduling each time as described above. Legacy applications whose targetSdkVersion is earlier than API 19 will continue to have all of their alarms, including repeating alarms, treated as exact.

可见在API 19的版本中重复报警也是不准确的,不过文档中倒是给我们提供的一个解决方案,不去使用setRepeating方法,而是用set方法去模拟这个功能,在每一次闹钟启动的时候我们人为地去使用set设置下一次闹钟响铃的时间。
别说,这样做了之后闹钟还真是正常了好多呢。

解决办法

针对于Android闹钟启动时间不准时,可以把 setsetRepeating使用setExact来代替,这种只会启动一次闹钟,如果要设置重复,则应该使用上述的方法在每次启动闹钟的时候设置下一次的闹钟。

不过使用这种方法会增加系统的功耗。

但是闹钟的准时与否也和好多因素有关,我在实验的过程中就发现,手机是否在充电会有影响,充电时比较准,闹钟设置重复的间隔太小也会影响,通常间隔越大越会准时一些。

以上

Android 4.4是经历了什么,不过鱼与熊掌不可兼得,如果既要使用系统计步功能还要使用准时的闹钟功能的可就要好好考虑一下了。