文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android实现简易计步器功能隔天步数清零查看历史运动纪录

2023-05-31 02:18

关注

最近需要用到计步功能,这可难坏我了,iOS端倒好,有自带的计步功能,让我惊讶的是连已爬楼层都给做好了,只需要调接口便可获得数据,我有一句MMP,我很想讲。

但是抱怨归抱怨,功能还是得事先的去实现,微信运动,乐动力,都还不错,尤其是乐动力的计步功能真的非常的强大,在UI域用户与用户交互也做得非常棒,党来内需当连续运动十步后开始计步。本想着去找他们实现的算法然后拿来用,但很明显这是不可能的。后来我搜了很多资料发现,在Android4.4 Kitkat 新增的STEP DETECTOR 以及 STEP COUNTER传感器。但是!Android的这个传感器虽然可以计步,但是所记录的步数是从你开机之时开始计算,不断累加,隔天也不会清零,并且,一旦关机后,传感器记录的数据也就清空了!这就很尴尬了,不过既然直接使用传感器数据不行,那我们就自己动手,将数据按天来保存~接下来进入正题,皮皮猿,我们走起~

先来看下我们需要解决的点有:

步数从开机之后不断累加,关机之后便清零,步数不能隔天清零

不能查看历史数据

这就好办了。我们只需将当前传感器记录的步数以每天为单位存进数据库,如果更新的步数为当天的则去更新数据库!先来看下我的界面(Demo在文章最后):

Android实现简易计步器功能隔天步数清零查看历史运动纪录   Android实现简易计步器功能隔天步数清零查看历史运动纪录   Android实现简易计步器功能隔天步数清零查看历史运动纪录    

第一二张图为界面效果图,数据均是从数据取出绘制在界面上,第三张图为设置前台进程时所设置的Notification样式,当然了这个可以去自定义样式,再此我就不详细解释了。

工程的目录结构如下:

Android实现简易计步器功能隔天步数清零查看历史运动纪录

其中主要的代码都在StepService.class 中了,其中注释也都非常详细,我就直接放代码了:

 public class StepService extends Service implements SensorEventListener {   public static final String TAG = "StepService";   //当前日期   private static String CURRENT_DATE;   //当前步数   private int CURRENT_STEP;   //3秒进行一次存储   private static int saveDuration = 3000;   //传感器   private SensorManager sensorManager;   //数据库   private StepDataDao stepDataDao;   //计步传感器类型 0-counter 1-detector   private static int stepSensor = -1;   //广播接收   private BroadcastReceiver mInfoReceiver;   //自定义简易计时器   private TimeCount timeCount;   //发送消息,用来和Service之间传递步数   private Messenger messenger = new Messenger(new MessengerHandler());   //是否有当天的记录   private boolean hasRecord;   //未记录之前的步数   private int hasStepCount;   //下次记录之前的步数   private int previousStepCount;   private Notification.Builder builder;   private NotificationManager notificationManager;   private Intent nfIntent;   @Override   public void onCreate() {     super.onCreate();     initBroadcastReceiver();     new Thread(new Runnable() {       public void run() {         getStepDetector();       }     }).start();     startTimeCount();     initTodayData();   }   @Nullable   @Override   public IBinder onBind(Intent intent) {     return messenger.getBinder();   }   @Override   public int onStartCommand(Intent intent, int flags, int startId) {          notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);     //获取一个Notification构造器     builder = new Notification.Builder(this.getApplicationContext());          nfIntent = new Intent(this, MainActivity.class);     builder.setContentIntent(PendingIntent.getActivity(this, 0, nfIntent, 0)) // 设置PendingIntent         .setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher)) // 设置下拉列表中的图标(大图标)         .setContentTitle("今日步数"+CURRENT_STEP+"步") // 设置下拉列表里的         .setSmallIcon(R.mipmap.ic_launcher) // 设置状态栏内的小图标         .setContentText("加油,要记得勤加运动"); // 设置上下文内容     // 获取构建好的Notification     Notification stepNotification = builder.build();     notificationManager.notify(110,stepNotification);     // 参数一:唯一的通知标识;参数二:通知消息。     startForeground(110, stepNotification);// 开始前台服务     return START_STICKY;   }      private class MessengerHandler extends Handler {     @Override     public void handleMessage(Message msg) {       switch (msg.what) {         case Constant.MSG_FROM_CLIENT:           try {             //这里负责将当前的步数发送出去,可以在界面或者其他地方获取,我这里是在MainActivity中获取来更新界面             Messenger messenger = msg.replyTo;             Message replyMsg = Message.obtain(null, Constant.MSG_FROM_SERVER);             Bundle bundle = new Bundle();             bundle.putInt("steps", CURRENT_STEP);             replyMsg.setData(bundle);             messenger.send(replyMsg);           } catch (RemoteException e) {             e.printStackTrace();           }           break;         default:           super.handleMessage(msg);       }     }   }      private void initBroadcastReceiver() {     final IntentFilter filter = new IntentFilter();     // 屏幕灭屏广播     filter.addAction(Intent.ACTION_SCREEN_OFF);     //关机广播     filter.addAction(Intent.ACTION_SHUTDOWN);     // 屏幕解锁广播     filter.addAction(Intent.ACTION_USER_PRESENT);     // 当长按电源键弹出“关机”对话或者锁屏时系统会发出这个广播     // example:有时候会用到系统对话框,权限可能很高,会覆盖在锁屏界面或者“关机”对话框之上,     // 所以监听这个广播,当收到时就隐藏自己的对话,如点击pad右下角部分弹出的对话框     filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);     //监听日期变化     filter.addAction(Intent.ACTION_DATE_CHANGED);     filter.addAction(Intent.ACTION_TIME_CHANGED);     filter.addAction(Intent.ACTION_TIME_TICK);     mInfoReceiver = new BroadcastReceiver() {       @Override       public void onReceive(Context context, Intent intent) {         String action = intent.getAction();         switch (action) {           // 屏幕灭屏广播           case Intent.ACTION_SCREEN_OFF:             //屏幕熄灭改为10秒一存储             saveDuration = 10000;             break;           //关机广播,保存好当前数据           case Intent.ACTION_SHUTDOWN:             saveStepData();             break;           // 屏幕解锁广播           case Intent.ACTION_USER_PRESENT:             saveDuration = 3000;             break;           // 当长按电源键弹出“关机”对话或者锁屏时系统会发出这个广播           // example:有时候会用到系统对话框,权限可能很高,会覆盖在锁屏界面或者“关机”对话框之上,           // 所以监听这个广播,当收到时就隐藏自己的对话,如点击pad右下角部分弹出的对话框           case Intent.ACTION_CLOSE_SYSTEM_DIALOGS:             saveStepData();             break;           //监听日期变化           case Intent.ACTION_DATE_CHANGED:           case Intent.ACTION_TIME_CHANGED:           case Intent.ACTION_TIME_TICK:             saveStepData();             isNewDay();             break;           default:             break;         }       }     };     //注册广播     registerReceiver(mInfoReceiver, filter);   }      private void initTodayData() {     //获取当前时间     CURRENT_DATE = TimeUtil.getCurrentDate();     //获取数据库     stepDataDao = new StepDataDao(getApplicationContext());     //获取当天的数据,用于展示     StepEntity entity = stepDataDao.getCurDataByDate(CURRENT_DATE);     //为空则说明还没有该天的数据,有则说明已经开始当天的计步了     if (entity == null) {       CURRENT_STEP = 0;     } else {       CURRENT_STEP = Integer.parseInt(entity.getSteps());     }   }      private void isNewDay() {     String time = "00:00";     if (time.equals(new SimpleDateFormat("HH:mm").format(new Date())) ||         !CURRENT_DATE.equals(TimeUtil.getCurrentDate())) {       initTodayData();     }   }      private void getStepDetector() {     if (sensorManager != null) {       sensorManager = null;     }     // 获取传感器管理器的实例     sensorManager = (SensorManager) this         .getSystemService(SENSOR_SERVICE);     //android4.4以后可以使用计步传感器     int VERSION_CODES = Build.VERSION.SDK_INT;     if (VERSION_CODES >= 19) {       addCountStepListener();     }   }      private void addCountStepListener() {     Sensor countSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);     Sensor detectorSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);     if (countSensor != null) {       stepSensor = 0;       sensorManager.registerListener(StepService.this, countSensor, SensorManager.SENSOR_DELAY_NORMAL);     } else if (detectorSensor != null) {       stepSensor = 1;       sensorManager.registerListener(StepService.this, detectorSensor, SensorManager.SENSOR_DELAY_NORMAL);     }   }      @Override   public void onSensorChanged(SensorEvent event) {     if (stepSensor == 0) {       int tempStep = (int) event.values[0];       if (!hasRecord) {         hasRecord = true;         hasStepCount = tempStep;       } else {         int thisStepCount = tempStep - hasStepCount;         CURRENT_STEP += (thisStepCount - previousStepCount);         previousStepCount = thisStepCount;       }     } else if (stepSensor == 1) {       if (event.values[0] == 1.0) {         CURRENT_STEP++;       }     }   }   @Override   public void onAccuracyChanged(Sensor sensor, int accuracy) {   }      private void startTimeCount() {     timeCount = new TimeCount(saveDuration, 1000);     timeCount.start();   }   private class TimeCount extends CountDownTimer {          public TimeCount(long millisInFuture, long countDownInterval) {       super(millisInFuture, countDownInterval);     }     @Override     public void onTick(long millisUntilFinished) {     }     @Override     public void onFinish() {       // 如果计时器正常结束,则每隔三秒存储步数到数据库       timeCount.cancel();       saveStepData();       startTimeCount();     }   }      private void saveStepData() {     //查询数据库中的数据     StepEntity entity = stepDataDao.getCurDataByDate(CURRENT_DATE);     //为空则说明还没有该天的数据,有则说明已经开始当天的计步了     if (entity == null) {       //没有则新建一条数据       entity = new StepEntity();       entity.setCurDate(CURRENT_DATE);       entity.setSteps(String.valueOf(CURRENT_STEP));       stepDataDao.addNewData(entity);     } else {       //有则更新当前的数据       entity.setSteps(String.valueOf(CURRENT_STEP));       stepDataDao.updateCurData(entity);     }     builder.setContentIntent(PendingIntent.getActivity(this, 0, nfIntent, 0)) // 设置PendingIntent         .setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher)) // 设置下拉列表中的图标(大图标)         .setContentTitle("今日步数"+CURRENT_STEP+"步") // 设置下拉列表里的         .setSmallIcon(R.mipmap.ic_launcher) // 设置状态栏内的小图标         .setContentText("加油,要记得勤加运动"); // 设置上下文内容      // 获取构建好的Notification     Notification stepNotification = builder.build();     //调用更新     notificationManager.notify(110,stepNotification);   }   @Override   public void onDestroy() {     super.onDestroy();     //主界面中需要手动调用stop方法service才会结束     stopForeground(true);     unregisterReceiver(mInfoReceiver);   }   @Override   public boolean onUnbind(Intent intent) {     return super.onUnbind(intent);   } } 

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 资料下载
  • 历年真题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯