Android计步器的实现(2)
2016-11-28 16:17
926 查看
上一篇见:
Android计步器的实现(1)
2.时间戳工具
public abstract class Util4Pedometer { /** * @return milliseconds since 1.1.1970 for today 0:00:00 */ public static long getToday() { Calendar c = Calendar.getInstance(); c.setTimeInMillis(System.currentTimeMillis()); c.set(Calendar.HOUR_OF_DAY, 0); c.set(Calendar.MINUTE, 0); c.set(Calendar.SECOND, 0); c.set(Calendar.MILLISECOND, 0); return c.getTimeInMillis(); } }
3.获取当天的步数
以往的步数建议服务器获取。 获取当天步数代码:
/** * 使用该方法前必须对context进行初始化 */ public class StepsCountTool { public static Context context; /** * 获得当天的步数,若步数异常重置步数 * 这里返回String是因为方便往服务器提交数据时加密(如:RSA) */ public static String getTodaySteps() { if (null == context) { return "0"; } int result = 0; Database db = Database.getInstance(context); long today = Util4Pedometer.getToday(); // 当天步数为当天的steps数据与sensor数据之和 result = db.getSteps(today) + db.getSensorSteps(today); if (0 > result) { // 说明数据异常(只有在跨天且计步器逻辑没有被触发才有可能异常,此处触发几率不大,保险起见, // 看计步器服务调用该方法的位置可理解),应该重置当前的步数 db.updateSteps(today, -db.getSteps(today)); db.updateSensorSteps(today, 0); result = 0; } return result + ""; } }
4.计步器服务的实现
计步器要一直在后台运行就使用到了Service,如果不能一直运行则某些情况会使计数偏小,关于如何保活,这是个问题,这里只尽可能的使服务唤醒 (请自行解决,最后会给出源码,仅供参考)。 计步服务代码:
@TargetApi(Build.VERSION_CODES.KITKAT) public class SensorListener extends Service implements SensorEventListener { public static boolean isShutdowning = false;// 只有接收到关机广播才会置为true private Database db; public static int steps = 0; private final static int MICROSECONDS_IN_ONE_MINUTE = 60000000; @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @Override public void onSensorChanged(final SensorEvent event) { // 关机时不往下执行 if (isShutdowning) { return; } // 若步数异常(用户随意调整时间后,开关机等等),修复步数 StepsCountTool.getTodaySteps(); Sensor sensor = event.sensor; if (sensor.getType() != Sensor.TYPE_STEP_COUNTER) { return; } steps = (int) event.values[0]; db = Database.getInstance(this); long today = Util4Pedometer.getToday(); long yesterDay = today - 24 * 60 * 60 * 1000; int correctSensorSteps; int off = db.getOffStatus(yesterDay); if (off == 0) { // 说明昨天没有关机,得到修正值:当前计步器数据 - 上一天sensor修正值,手机异常关机,会使steps的值从0开始 // 正常情况correctSensorSteps 为正 correctSensorSteps = steps - db.getSensorSteps(yesterDay); if (correctSensorSteps < 0) { // 说明手机异常关机:扣电池或使用脚本关机导致关机广播没有发出,正常关机时会将所有off置为1, db.updateOffStatus(yesterDay, 1); // 异常关机后重启先保存关机前的数据 db.updateSteps(today, db.getSensorSteps(today)); // 再重新计算步数,这样能最大可能的接近真实值,此时steps从1开始 db.updateSensorSteps(today, steps); } else { // 如果没有关机,跨天时一定会执行if中的代码,因为insertNewDay的sensor和steps的参数都是0, // 在第一次监听到计步器改变时,senor的值还未改变 if (db.getSensorSteps(today) <= 0) { // 这里每天只更新一次sensor,更新后和sensor的和为0,跨天问题解决 // steps此时为0,将sensor偏移量取反放入steps中, db.updateSteps(today, -correctSensorSteps); } db.updateSensorSteps(today, correctSensorSteps); } } else if (off == 1) { // 说明昨天关机,correctSensorSteps 就是传感器的真实值 correctSensorSteps = steps; db.updateSensorSteps(today, correctSensorSteps); } else { // 计步器异常 } } @Override public IBinder onBind(final Intent intent) { return null; } @Override public int onStartCommand(final Intent intent, int flags, int startId) { if (isShutdowning) { return START_STICKY; } db = Database.getInstance(this); // 每次启动服务都将今天的状态置为0 db.updateOffStatus(Util4Pedometer.getToday(), 0); // restart service every hour to get the current step count ((AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE)) .set(AlarmManager.RTC, System.currentTimeMillis() + AlarmManager.INTERVAL_HOUR, PendingIntent.getService(getApplicationContext(), 2, new Intent(this, SensorListener.class), PendingIntent.FLAG_UPDATE_CURRENT)); return START_STICKY; } @Override public void onCreate() { super.onCreate(); reRegisterSensor(); } @Override public void onTaskRemoved(final Intent rootIntent) { super.onTaskRemoved(rootIntent); // Restart service in 500 ms ((AlarmManager) getSystemService(Context.ALARM_SERVICE)) .set(AlarmManager.RTC, System.currentTimeMillis() + 500, PendingIntent .getService(this, 3, new Intent(this, SensorListener.class), 0)); } @Override public void onDestroy() { super.onDestroy(); if (null != db) { db.close(); } try { SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE); sm.unregisterListener(this); } catch (Exception e) { e.printStackTrace(); } reRegisterSensor(); } @TargetApi(19) private void reRegisterSensor() { if (Build.VERSION.SDK_INT < 19) { return; } SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE); if (null == sm) { // 无法获得传感器管理组件 } else { // 获得传感器管理组件 } try { sm.unregisterListener(this); } catch (Exception e) { e.printStackTrace(); } if (null == sm.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)) { // 没有计步器 } else { // 有计步器 } sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_STEP_COUNTER), SensorManager.SENSOR_DELAY_NORMAL, 5 * MICROSECONDS_IN_ONE_MINUTE); } }
5.手机正常关机的处理
/** * 监听到关机广播后,如下处理 */ public class ShutdownReceiver extends BroadcastReceiver { @TargetApi(Build.VERSION_CODES.KITKAT) @Override public void onReceive(final Context context, final Intent intent) { // 如果没接收到关机广播直接退出等下次启动时重新初始化 if (!"android.intent.action.ACTION_SHUTDOWN".equals(intent.getAction())) { return; } // if the user used a root script for shutdown, the DEVICE_SHUTDOWN // broadcast might not be send. Therefore, the app will check this // setting on the next boot and displays an error message if it's not // set to true // 然而异常关机和正常安装app无法区分,此sp暂时无用 context.getSharedPreferences("pedometer", Context.MODE_PRIVATE).edit() .putBoolean("correctShutdown", true).commit(); // 接收到关机广播的时候SensorListener不应该再执行 SensorListener.isShutdowning = true; Database db = Database.getInstance(context); long today = Util4Pedometer.getToday(); long yesterDay = today - 24 * 60 * 60 * 1000; int correctSensorSteps = 0; int off = db.getOffStatus(yesterDay); if (off == 0) { // 说明昨天没有关机 correctSensorSteps = SensorListener.steps - db.getSensorSteps(yesterDay); // 将今天的步数存入steps偏移量中,传入correctSensorSteps后会加上steps自身,详见Database代码 db.updateSteps(today, correctSensorSteps); } else if (off == 1) { // 说明昨天关机,偏移量就是计步器的实际值 correctSensorSteps = SensorListener.steps; db.updateSteps(today, correctSensorSteps); } else { // 计步器异常 } // 将今天的sensor偏移量置为0,下面这三行代码是为了解决在关机时更新整个数据库不能完成的情况, // 这样在用户不随意修改系统时间时可以最优处理 db.updateSensorSteps(today, 0); db.updateOffStatus(yesterDay, 1); db.updateOffStatus(today, 1); // 更新整个数据库将off置为1,sensor置为0, steps置为每天的步数 db.updateAll(); db.close(); } }
到这里大体思路都实现了,其他代码等我发布源码后查看。
相关文章推荐
- Android实现简易计步器功能,隔天步数清零,查看历史运动纪录
- Android移动开发-调用步行检测和步行计数传感器开发简易计步器的实现
- Android计步器的实现(1)
- Android实现简易计步器功能隔天步数清零查看历史运动纪录
- Android实现简易计步器功能,隔天步数清零,查看历史运动纪录
- Android教程之实现动作感应技术
- Android中实现物体在屏幕的移动
- Android开发者教程1: 实现一个登录对话框
- Android下代码实现APN管理设置
- 实现一个登录对话框 (Android开发)
- 使用 Android 实现联网
- Android下代码实现APN管理设置
- Android 实例-个人理财工具 之一 启动界面实现
- 主题:利用Bundle实现Android Activity间消息的传递
- [转载]利用Bundle实现Android Activity间消息的传递
- Android下媒体库的实现
- Android应用程序开发教程 - 实现一个登录对话框
- [转载]Android下实现程序关闭后,监听取消
- android技巧:手写输入的联想输入实现
- 基于rtsp的手机视频点播实现和研究(扩展支持android, ios平台)