软件编程
位置:首页>> 软件编程>> Android编程>> Android实现简易计步器功能隔天步数清零查看历史运动纪录

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

作者:IT随笔  发布时间:2021-07-24 00:37:02 

标签:android,计步器

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

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

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

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

2、不能查看历史数据

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

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

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

工程的目录结构如下:

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

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


/**
* Created by fySpring
* Date : 2017/3/24
* To do :
*/
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) {
   /**
    * 此处设将Service为前台,不然当APP结束以后很容易被GC给干掉,这也就是大多数音乐播放器会在状态栏设置一个
    * 原理大都是相通的
    */
   notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
   //获取一个Notification构造器
   builder = new Notification.Builder(this.getApplicationContext());
   /**
    * 设置点击通知栏打开的界面,此处需要注意了,如果你的计步界面不在主界面,则需要判断app是否已经启动,
    * 再来确定跳转页面,这里面太多坑,(别问我为什么知道 - -)
    * 总之有需要的可以和我交流
    */
   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;
 }
 /**
  * 自定义handler
  */
 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());
   }
 }
 /**
  * 监听晚上0点变化初始化数据
  */
 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);
   }
 }
 /**
  * 由传感器记录当前用户运动步数,注意:该传感器只在4.4及以后才有,并且该传感器记录的数据是从设备开机以后不断累加,
  * 只有当用户关机以后,该数据才会清空,所以需要做数据保护
  *
  * @param event
  */
 @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 {
   /**
    * @param millisInFuture  The number of millis in the future from the call
    *             to {@link #start()} until the countdown is done and {@link #onFinish()}
    *             is called.
    * @param countDownInterval The interval along the way to receive
    *             {@link #onTick(long)} callbacks.
    */
   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);
 }
}

其中关于四大组件之一的Service也有很多要去学习的,这几天也是恶补了一下,算是弥补当年在学校没有仔细学习这一块的遗憾吧 - -

主要要说的就是以上了,源码在这里源码点我点我

以上所述是小编给大家介绍的Android实现简易计步器功能隔天步数清零查看历史运动纪录网站的支持!

来源:http://blog.csdn.net/qq_21051503/article/details/73064990

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com